From dbf247ec63dabd36b89fb1a4ea3d71d6c5bbe41e Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Fri, 19 Nov 2021 12:53:40 +0100 Subject: [PATCH 1/5] Minor pthread cleanups. NFC --- src/struct_info_internal.json | 6 ++--- system/lib/libc/musl/src/thread/__timedwait.c | 6 ++--- system/lib/libc/musl/src/thread/__wait.c | 3 +-- .../musl/src/thread/pthread_barrier_wait.c | 2 +- .../lib/libc/musl/src/thread/pthread_detach.c | 3 ++- .../libc/musl/src/thread/pthread_key_create.c | 4 --- system/lib/libc/musl/src/thread/thrd_create.c | 2 -- system/lib/pthread/library_pthread.c | 25 +++++-------------- system/lib/pthread/pthread_create.c | 13 +++++----- system/lib/pthread/threading_internal.h | 2 +- test/pthread/main_thread_join.cpp | 2 +- 11 files changed, 23 insertions(+), 45 deletions(-) diff --git a/src/struct_info_internal.json b/src/struct_info_internal.json index 4681b77fe55a0..de28e7a0b6c4c 100644 --- a/src/struct_info_internal.json +++ b/src/struct_info_internal.json @@ -15,9 +15,9 @@ "_a_transferredcanvases" ], "thread_profiler_block": [ - "threadStatus", - "timeSpentInStatus", - "name" + "threadStatus", + "timeSpentInStatus", + "name" ] } }, diff --git a/system/lib/libc/musl/src/thread/__timedwait.c b/system/lib/libc/musl/src/thread/__timedwait.c index 9e3ccc9849257..2c82d2ab1e8c0 100644 --- a/system/lib/libc/musl/src/thread/__timedwait.c +++ b/system/lib/libc/musl/src/thread/__timedwait.c @@ -2,13 +2,11 @@ #include #include #ifdef __EMSCRIPTEN__ -#include -#include -#include +#include // for INFINITY #else #include "futex.h" -#endif #include "syscall.h" +#endif #include "pthread_impl.h" #ifndef __EMSCRIPTEN__ diff --git a/system/lib/libc/musl/src/thread/__wait.c b/system/lib/libc/musl/src/thread/__wait.c index 66a140bd69401..fe3b5cf38b071 100644 --- a/system/lib/libc/musl/src/thread/__wait.c +++ b/system/lib/libc/musl/src/thread/__wait.c @@ -1,6 +1,5 @@ #ifdef __EMSCRIPTEN__ -#include -#include +#include // for INFINITY #endif #include "pthread_impl.h" diff --git a/system/lib/libc/musl/src/thread/pthread_barrier_wait.c b/system/lib/libc/musl/src/thread/pthread_barrier_wait.c index 0d73d7fd33267..b7f3b96326c7e 100644 --- a/system/lib/libc/musl/src/thread/pthread_barrier_wait.c +++ b/system/lib/libc/musl/src/thread/pthread_barrier_wait.c @@ -1,5 +1,5 @@ #ifdef __EMSCRIPTEN__ -#include +#include // for INFINITY #endif #include "pthread_impl.h" diff --git a/system/lib/libc/musl/src/thread/pthread_detach.c b/system/lib/libc/musl/src/thread/pthread_detach.c index c25882cca4ac1..2b516e232db06 100644 --- a/system/lib/libc/musl/src/thread/pthread_detach.c +++ b/system/lib/libc/musl/src/thread/pthread_detach.c @@ -32,5 +32,6 @@ static int __pthread_detach(pthread_t t) weak_alias(__pthread_detach, pthread_detach); weak_alias(__pthread_detach, thrd_detach); -// XXX EMSCRIPTEN: add extra alias for asan. +#ifdef __EMSCRIPTEN__ // XXX Emscripten add an extra alias for ASan/LSan. weak_alias(__pthread_detach, emscripten_builtin_pthread_detach); +#endif diff --git a/system/lib/libc/musl/src/thread/pthread_key_create.c b/system/lib/libc/musl/src/thread/pthread_key_create.c index f45553919647a..39770c7a3c829 100644 --- a/system/lib/libc/musl/src/thread/pthread_key_create.c +++ b/system/lib/libc/musl/src/thread/pthread_key_create.c @@ -1,10 +1,6 @@ #include "pthread_impl.h" #include "fork_impl.h" -#ifdef __EMSCRIPTEN__ -#include -#endif - volatile size_t __pthread_tsd_size = sizeof(void *) * PTHREAD_KEYS_MAX; void *__pthread_tsd_main[PTHREAD_KEYS_MAX] = { 0 }; diff --git a/system/lib/libc/musl/src/thread/thrd_create.c b/system/lib/libc/musl/src/thread/thrd_create.c index ca4efb661973b..d1191660a292d 100644 --- a/system/lib/libc/musl/src/thread/thrd_create.c +++ b/system/lib/libc/musl/src/thread/thrd_create.c @@ -6,8 +6,6 @@ // if we call the internal __pthread_create function here to don't the wrapping // See pthread_create wrapper in compiler-rt/lib/lsan/lsan_interceptors.cpp. #define __pthread_create pthread_create -#else -int __pthread_create(pthread_t *restrict, const pthread_attr_t *restrict, void *(*)(void *), void *restrict); #endif int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c index 0a47e1a4dd863..648ea842c140b 100644 --- a/system/lib/pthread/library_pthread.c +++ b/system/lib/pthread/library_pthread.c @@ -5,27 +5,13 @@ * found in the LICENSE file. */ -#define _GNU_SOURCE -#include "../internal/libc.h" -#include "../internal/pthread_impl.h" +#include "libc.h" +#include "pthread_impl.h" #include -#include -#include -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include #include #include @@ -128,15 +114,16 @@ void _emscripten_init_main_thread(void) { // a magic ID to detect whether the pthread_t structure is 'alive'. __main_pthread.self = &__main_pthread; __main_pthread.detach_state = DT_JOINABLE; - // pthread struct robust_list head should point to itself. - __main_pthread.robust_list.head = &__main_pthread.robust_list.head; // Main thread ID is always 1. It can't be 0 because musl assumes // tid is always non-zero. __main_pthread.tid = getpid(); + // Initialize thread-specific data area. + __main_pthread.tsd = (void **)__pthread_tsd_main; + // pthread struct robust_list head should point to itself. + __main_pthread.robust_list.head = &__main_pthread.robust_list.head; // pthread struct prev and next should initially point to itself (see __init_tp), // this is used by pthread_key_delete for deleting thread-specific data. __main_pthread.next = __main_pthread.prev = &__main_pthread; - __main_pthread.tsd = (void **)__pthread_tsd_main; _emscripten_init_main_thread_js(&__main_pthread); diff --git a/system/lib/pthread/pthread_create.c b/system/lib/pthread/pthread_create.c index 00df6ad4b8854..450261d1ae52f 100644 --- a/system/lib/pthread/pthread_create.c +++ b/system/lib/pthread/pthread_create.c @@ -5,7 +5,6 @@ * found in the LICENSE file. */ -#define _GNU_SOURCE #include "pthread_impl.h" #include "stdio_impl.h" #include "assert.h" @@ -108,7 +107,7 @@ int __pthread_create(pthread_t* restrict res, void* (*entry)(void*), void* restrict arg) { // Note on LSAN: lsan intercepts/wraps calls to pthread_create so any - // allocation we do here should be considered leaks. + // allocation we do here should be considered as leak. // See: lsan_interceptors.cpp. if (!res) { return EINVAL; @@ -292,10 +291,10 @@ void _emscripten_thread_free_data(pthread_t t) { } void _emscripten_thread_exit(void* result) { - struct pthread *self = __pthread_self(); + pthread_t self = __pthread_self(); assert(self); - self->canceldisable = PTHREAD_CANCEL_DISABLE; + self->canceldisable = 1; self->cancelasync = 0; self->result = result; @@ -344,8 +343,8 @@ void _emscripten_thread_exit(void* result) { // 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,7 +362,7 @@ void _emscripten_thread_exit(void* result) { } } -// Mark as `no_sanitize("address"` since emscripten_pthread_exit destroys +// Mark as `no_sanitize("address")` since emscripten_pthread_exit destroys // the current thread and runs its exit handlers. Without this asan injects // a call to __asan_handle_no_return before emscripten_unwind_to_js_event_loop // which seem to cause a crash later down the line. diff --git a/system/lib/pthread/threading_internal.h b/system/lib/pthread/threading_internal.h index dca84b299d418..056ebb9f6daa3 100644 --- a/system/lib/pthread/threading_internal.h +++ b/system/lib/pthread/threading_internal.h @@ -105,7 +105,7 @@ void emscripten_conditional_set_current_thread_status(EM_THREAD_STATUS expectedS #endif int __pthread_kill_js(pthread_t t, int sig); -int __pthread_create_js(struct __pthread *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); +int __pthread_create_js(pthread_t thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); int _emscripten_default_pthread_stack_size(); void __set_thread_state(pthread_t ptr, int is_main, int is_runtime, int can_block); diff --git a/test/pthread/main_thread_join.cpp b/test/pthread/main_thread_join.cpp index afa611aaf7ad5..ece9c74d59920 100644 --- a/test/pthread/main_thread_join.cpp +++ b/test/pthread/main_thread_join.cpp @@ -33,7 +33,7 @@ void *ThreadMain(void *arg) { // succeeding. while (tries.load() < EXPECTED_TRIES) {} #endif - pthread_exit((void*)0); + pthread_exit((void*)0); } pthread_t CreateThread() { From a514a874f3e474bfc907e0d0e525b624e1a795e0 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Tue, 5 May 2026 11:23:08 +0000 Subject: [PATCH 2/5] Automatic rebaseline of codesize expectations. NFC This is an automatic change generated by tools/maint/rebaseline_tests.py. The following (1) test expectation files were updated by running the tests with `--rebaseline`: ``` codesize/test_codesize_minimal_pthreads.json: 26370 => 26370 [+0 bytes / +0.00%] Average change: +0.00% (+0.00% - +0.00%) ``` --- test/codesize/test_codesize_minimal_pthreads.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/codesize/test_codesize_minimal_pthreads.json b/test/codesize/test_codesize_minimal_pthreads.json index 73c3e5be27176..1a7111d36c45a 100644 --- a/test/codesize/test_codesize_minimal_pthreads.json +++ b/test/codesize/test_codesize_minimal_pthreads.json @@ -2,9 +2,9 @@ "a.out.js": 7323, "a.out.js.gz": 3573, "a.out.nodebug.wasm": 19047, - "a.out.nodebug.wasm.gz": 8794, + "a.out.nodebug.wasm.gz": 8795, "total": 26370, - "total_gz": 12367, + "total_gz": 12368, "sent": [ "a (memory)", "b (exit)", From 97cdf890ca3d4758e6eb6380e2edeae5648be664 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Tue, 5 May 2026 17:36:36 +0200 Subject: [PATCH 3/5] Revert accidental re-ordering --- system/lib/pthread/library_pthread.c | 8 ++++---- test/codesize/test_codesize_minimal_pthreads.json | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c index 648ea842c140b..b8a48cb91f1c9 100644 --- a/system/lib/pthread/library_pthread.c +++ b/system/lib/pthread/library_pthread.c @@ -114,16 +114,16 @@ void _emscripten_init_main_thread(void) { // a magic ID to detect whether the pthread_t structure is 'alive'. __main_pthread.self = &__main_pthread; __main_pthread.detach_state = DT_JOINABLE; + // pthread struct robust_list head should point to itself. + __main_pthread.robust_list.head = &__main_pthread.robust_list.head; // Main thread ID is always 1. It can't be 0 because musl assumes // tid is always non-zero. __main_pthread.tid = getpid(); - // Initialize thread-specific data area. - __main_pthread.tsd = (void **)__pthread_tsd_main; - // pthread struct robust_list head should point to itself. - __main_pthread.robust_list.head = &__main_pthread.robust_list.head; // pthread struct prev and next should initially point to itself (see __init_tp), // this is used by pthread_key_delete for deleting thread-specific data. __main_pthread.next = __main_pthread.prev = &__main_pthread; + // Initialize thread-specific data area. + __main_pthread.tsd = (void **)__pthread_tsd_main; _emscripten_init_main_thread_js(&__main_pthread); diff --git a/test/codesize/test_codesize_minimal_pthreads.json b/test/codesize/test_codesize_minimal_pthreads.json index 1a7111d36c45a..73c3e5be27176 100644 --- a/test/codesize/test_codesize_minimal_pthreads.json +++ b/test/codesize/test_codesize_minimal_pthreads.json @@ -2,9 +2,9 @@ "a.out.js": 7323, "a.out.js.gz": 3573, "a.out.nodebug.wasm": 19047, - "a.out.nodebug.wasm.gz": 8795, + "a.out.nodebug.wasm.gz": 8794, "total": 26370, - "total_gz": 12368, + "total_gz": 12367, "sent": [ "a (memory)", "b (exit)", From 3ea99f277d7d7de31f8bb234d2540af81bc08b8a Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Wed, 6 May 2026 20:07:44 +0200 Subject: [PATCH 4/5] Feedback --- system/lib/pthread/pthread_create.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/lib/pthread/pthread_create.c b/system/lib/pthread/pthread_create.c index 450261d1ae52f..36bb56b74bbb1 100644 --- a/system/lib/pthread/pthread_create.c +++ b/system/lib/pthread/pthread_create.c @@ -107,7 +107,7 @@ int __pthread_create(pthread_t* restrict res, void* (*entry)(void*), void* restrict arg) { // Note on LSAN: lsan intercepts/wraps calls to pthread_create so any - // allocation we do here should be considered as leak. + // allocation we do here should not be considered as leak. // See: lsan_interceptors.cpp. if (!res) { return EINVAL; From fee0b4f4a1ca2c37e4c4899a84f3e1bbcd50ac24 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Wed, 6 May 2026 21:13:02 +0200 Subject: [PATCH 5/5] Feedback --- system/lib/pthread/pthread_create.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/lib/pthread/pthread_create.c b/system/lib/pthread/pthread_create.c index 36bb56b74bbb1..5fe3d9bdd90f7 100644 --- a/system/lib/pthread/pthread_create.c +++ b/system/lib/pthread/pthread_create.c @@ -107,7 +107,7 @@ int __pthread_create(pthread_t* restrict res, void* (*entry)(void*), void* restrict arg) { // Note on LSAN: lsan intercepts/wraps calls to pthread_create so any - // allocation we do here should not be considered as leak. + // allocations we do here should not be considered leaks. // See: lsan_interceptors.cpp. if (!res) { return EINVAL;