3232
3333static void dummy_0 () {}
3434weak_alias (dummy_0 , __pthread_tsd_run_dtors );
35+ weak_alias (dummy_0 , __do_orphaned_stdio_locks );
36+ weak_alias (dummy_0 , __dl_thread_cleanup );
3537
3638static void __run_cleanup_handlers () {
3739 pthread_t self = __pthread_self ();
@@ -306,11 +308,21 @@ void _emscripten_thread_exit(void* result) {
306308 // Call into the musl function that runs destructors of all thread-specific data.
307309 __pthread_tsd_run_dtors ();
308310
311+ // If this is the main runtime thread, don't proceed with
312+ // termination of the thread, but prepare for exit to call
313+ // atexit handlers.
314+ if (emscripten_is_main_runtime_thread ()) {
315+ exit (0 );
316+ }
317+
318+ // At this point we are committed to thread termination.
319+
320+ // The thread list lock must be AS-safe.
309321 __tl_lock ();
310322
311- /* Process robust list in userspace to handle non-pshared mutexes
312- * and the detached thread case where the robust list head will
313- * be invalid when the kernel would process it. */
323+ // Process robust list in userspace to handle non-pshared mutexes
324+ // and the detached thread case where the robust list head will
325+ // be invalid when the kernel would process it.
314326 __vm_lock ();
315327 volatile void * volatile * rp ;
316328 while ((rp = self -> robust_list .head ) && rp != & self -> robust_list .head ) {
@@ -327,19 +339,18 @@ void _emscripten_thread_exit(void* result) {
327339 }
328340 __vm_unlock ();
329341
330- if (!-- libc .threads_minus_1 ) libc .need_locks = 0 ;
342+ __do_orphaned_stdio_locks ();
343+ __dl_thread_cleanup ();
331344
345+ // Last, unlink thread from the list. This change will not be visible
346+ // until the lock is released via __tl_unlock() below.
347+ if (!-- libc .threads_minus_1 ) libc .need_locks = 0 ;
332348 self -> next -> prev = self -> prev ;
333349 self -> prev -> next = self -> next ;
334350 self -> prev = self -> next = self ;
335351
336352 __tl_unlock ();
337353
338- if (emscripten_is_main_runtime_thread ()) {
339- exit (0 );
340- return ;
341- }
342-
343354 // Not hosting a pthread anymore in this worker set __pthread_self to NULL
344355 __set_thread_state (NULL , 0 , 0 , 1 );
345356
@@ -357,8 +368,10 @@ void _emscripten_thread_exit(void* result) {
357368 // When dynamic linking is enabled we need to keep track of zombie threads
358369 _emscripten_thread_exit_joinable (self );
359370#endif
371+
372+ // Wake any joiner.
360373 a_store (& self -> detach_state , DT_EXITED );
361- __wake (& self -> detach_state , 1 , 1 ); // Wake any joiner.
374+ __wake (& self -> detach_state , 1 , 1 );
362375 }
363376}
364377
0 commit comments