From 986ba392eb7e31d5a6ce87a1885fc416f1e2d7e6 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 25 Feb 2026 11:55:46 -0800 Subject: [PATCH] [WASM_WORKERS] Don't define pthread function in WASM_WORKERS builds Using the pthread API with WASM_WORKERS simply will not work. --- ChangeLog.md | 4 +++ system/lib/libc/emscripten_yield_stub.c | 17 +++++++++++ system/lib/pthread/library_pthread_stub.c | 16 +++-------- test/test_other.py | 10 +++++++ test/wasm_worker/wasm_worker_cxx_init.cpp | 28 +++++++++++++++++++ .../wasm_worker_pthread_api_usage.c | 7 +++++ tools/system_libs.py | 21 ++++++++++---- 7 files changed, 85 insertions(+), 18 deletions(-) create mode 100644 system/lib/libc/emscripten_yield_stub.c create mode 100644 test/wasm_worker/wasm_worker_cxx_init.cpp create mode 100644 test/wasm_worker/wasm_worker_pthread_api_usage.c diff --git a/ChangeLog.md b/ChangeLog.md index 215691382cd96..eb1748c37658c 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,10 @@ See docs/process.md for more on how version tagging works. 5.0.3 (in development) ---------------------- +- When building with `-sWASM_WORKERS` emscripten will no longer include pthread + API stub functions. These stub functions where never designed to work under + Wasm Workers, so its safer to error at link time if pthread APIs are used + in Wasm Worker-based programs. (#26336) 5.0.2 - 02/25/26 ---------------- diff --git a/system/lib/libc/emscripten_yield_stub.c b/system/lib/libc/emscripten_yield_stub.c new file mode 100644 index 0000000000000..ac0d7498e7674 --- /dev/null +++ b/system/lib/libc/emscripten_yield_stub.c @@ -0,0 +1,17 @@ +/* + * Copyright 2026 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + */ + +#include + +static void dummy(double now) { +} + +weak_alias(dummy, _emscripten_check_timers); + +void _emscripten_yield(double now) { + _emscripten_check_timers(now); +} diff --git a/system/lib/pthread/library_pthread_stub.c b/system/lib/pthread/library_pthread_stub.c index 33e153a48677b..b0b2e83bb5475 100644 --- a/system/lib/pthread/library_pthread_stub.c +++ b/system/lib/pthread/library_pthread_stub.c @@ -17,11 +17,14 @@ #include #include +#ifdef __EMSCRIPTEN_WASM_WORKERS__ +#error "This file contains stubs that should not be included in wasm workers builds." +#endif + bool emscripten_has_threading_support() { return false; } int emscripten_num_logical_cores() { return 1; } -#ifndef __EMSCRIPTEN_WASM_WORKERS__ // These low level primites are defined in both pthreads and wasm workers // builds. @@ -55,7 +58,6 @@ void __unlock(void* ptr) {} void __acquire_ptc() {} void __release_ptc() {} -#endif void emscripten_main_thread_process_queued_calls() { // nop @@ -65,16 +67,6 @@ void emscripten_current_thread_process_queued_calls() { // nop } -static void dummy(double now) -{ -} - -weak_alias(dummy, _emscripten_check_timers); - -void _emscripten_yield(double now) { - _emscripten_check_timers(now); -} - int pthread_mutex_init( pthread_mutex_t* __restrict mutex, const pthread_mutexattr_t* __restrict attr) { return 0; diff --git a/test/test_other.py b/test/test_other.py index 804414e5c473d..0cb70e2a0311c 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13519,6 +13519,16 @@ def test_shared_memory_preprocessor_flags(self): def test_wasm_worker_preprocessor_flags(self): self.run_process([EMCC, '-c', test_file('wasm_worker/wasm_worker_preprocessor_flags.c'), '-sWASM_WORKERS']) + @also_with_minimal_runtime + def test_wasm_worker_pthread_api_usage(self): + self.assert_fail([EMCC, test_file('wasm_worker/wasm_worker_pthread_api_usage.c'), '-sWASM_WORKERS'], 'undefined symbol: pthread_mutex_lock') + + @also_with_minimal_runtime + def test_wasm_worker_cxx_init(self): + # For now, C++ init guards do not work with Wasm Workers. + # See https://github.com/emscripten-core/emscripten/issues/26277 + self.assert_fail([EMCC, test_file('wasm_worker/wasm_worker_cxx_init.cpp'), '-sWASM_WORKERS'], 'undefined symbol: pthread_cond_wait') + @parameterized({ # we will warn here since -O2 runs the optimizer and -g enables DWARF 'O2_g': (True, ['-O2', '-g']), diff --git a/test/wasm_worker/wasm_worker_cxx_init.cpp b/test/wasm_worker/wasm_worker_cxx_init.cpp new file mode 100644 index 0000000000000..c06dd051ea05c --- /dev/null +++ b/test/wasm_worker/wasm_worker_cxx_init.cpp @@ -0,0 +1,28 @@ +#include + +struct Foo { + Foo() { + printf("create Foo\n"); + } + + ~Foo() { + printf("destroy Foo\n"); + } + + void baz() { + printf("method called\n"); + } +}; + + +void bar() { + static Foo foo; + foo.baz(); +} + +int main() { + printf("main\n"); + bar(); + printf("done\n"); + return 0; +} diff --git a/test/wasm_worker/wasm_worker_pthread_api_usage.c b/test/wasm_worker/wasm_worker_pthread_api_usage.c new file mode 100644 index 0000000000000..61ddd7addbd60 --- /dev/null +++ b/test/wasm_worker/wasm_worker_pthread_api_usage.c @@ -0,0 +1,7 @@ +#include + +int main() { + // This program should fail to link with WASM_WORKERS. + pthread_mutex_t my_mutex = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock(&my_mutex); +} diff --git a/tools/system_libs.py b/tools/system_libs.py index 8eb285bcde86e..1e87dcaa5ec70 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1256,13 +1256,10 @@ def get_files(self): 'thrd_sleep.c', 'thrd_yield.c', ]) + libc_files += files_in_path( - path='system/lib/pthread', - filenames=[ - 'library_pthread_stub.c', - 'pthread_self_stub.c', - 'proxying_stub.c', - ]) + path='system/lib/libc', + filenames=['emscripten_yield_stub.c']) if self.is_ww: libc_files += files_in_path( @@ -1272,6 +1269,18 @@ def get_files(self): '__wait.c', 'lock_ptc.c', ]) + else: + # Include stub version of thread functions when building + # in single theaded mode. + # Note: We do *not* include these stubs in the Wasm Workers build since it would + # never be safe to call these from a Wasm Worker. + libc_files += files_in_path( + path='system/lib/pthread', + filenames=[ + 'library_pthread_stub.c', + 'pthread_self_stub.c', + 'proxying_stub.c', + ]) if self.is_mt or self.is_ww: # Low level thread primitives available in both pthreads and wasm workers builds.