From 88dbafc62809f9df639dd4e2cffbfb38897259ec Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 12 Mar 2026 15:17:30 -0700 Subject: [PATCH] Add some testing of the emscripten_condvar API. NFC --- test/test_browser.py | 4 ++ test/test_core.py | 5 ++ test/wasm_worker/condvar_waitinf.c | 99 ++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 test/wasm_worker/condvar_waitinf.c diff --git a/test/test_browser.py b/test/test_browser.py index 234d24b305287..9f601dd8a4355 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -5224,6 +5224,10 @@ def test_wasm_worker_semaphore_waitinf_acquire(self): def test_wasm_worker_semaphore_try_acquire(self): self.btest_exit('wasm_worker/semaphore_try_acquire.c', cflags=['-sWASM_WORKERS']) + @also_with_minimal_runtime + def test_wasm_worker_condvar_waitinf(self): + self.btest_exit('wasm_worker/condvar_waitinf.c', cflags=['-sWASM_WORKERS']) + # Tests that calling any proxied function in a Wasm Worker will abort at runtime when ASSERTIONS are enabled. def test_wasm_worker_proxied_function(self): error_msg = "abort:Assertion failed: Attempted to call proxied function '_proxied_js_function' in a Wasm Worker, but in Wasm Worker enabled builds, proxied function architecture is not available!" diff --git a/test/test_core.py b/test/test_core.py index c517d88fb4552..9e03c39a10f08 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -2794,6 +2794,11 @@ def test_emscripten_semaphore_waitinf_acquire(self): def test_emscripten_semaphore_try_acquire(self): self.do_runf('wasm_worker/semaphore_try_acquire.c', 'done\n', cflags=['-pthread']) + @requires_pthreads + @also_with_wasm_workers + def test_emscripten_condvar_waitinf(self): + self.do_runf('wasm_worker/condvar_waitinf.c', 'done\n', cflags=['-pthread']) + def test_tcgetattr(self): self.do_runf('termios/test_tcgetattr.c', 'success') diff --git a/test/wasm_worker/condvar_waitinf.c b/test/wasm_worker/condvar_waitinf.c new file mode 100644 index 0000000000000..2d6e8004f0fb8 --- /dev/null +++ b/test/wasm_worker/condvar_waitinf.c @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include + +#ifdef __EMSCRIPTEN_PTHREADS__ +#include +#else +#include +#endif + +emscripten_condvar_t condvar = EMSCRIPTEN_CONDVAR_T_STATIC_INITIALIZER; +emscripten_lock_t mutex = EMSCRIPTEN_LOCK_T_STATIC_INITIALIZER; + +int globalVar = 0; +_Atomic bool waiterStarted = false; + +#ifndef __EMSCRIPTEN_PTHREADS__ +void do_exit() { + emscripten_out("do_exit"); + emscripten_terminate_all_wasm_workers(); + emscripten_force_exit(0); +} +#endif + +void waiter_main() { + emscripten_out("waiter_main"); + emscripten_lock_waitinf_acquire(&mutex); + emscripten_out("waiter: got mutex"); + assert(!globalVar); + waiterStarted = true; + + while (!globalVar) { + emscripten_out("waiter: condvar wait"); + emscripten_condvar_waitinf(&condvar, &mutex); + } + + emscripten_out("waiter: done"); + emscripten_lock_release(&mutex); + +#ifndef __EMSCRIPTEN_PTHREADS__ + emscripten_wasm_worker_post_function_v(EMSCRIPTEN_WASM_WORKER_ID_PARENT, + do_exit); +#endif +} + +void signaler_main() { + emscripten_out("signaler_main"); + while (!waiterStarted) { + // busy-wait for waiter + } + // At this point we know the waiter took the lock already. + // That means that once we acquire the lock here the waiter + // muste be `emscripten_condvar_waitinf`. + + emscripten_out("signaler: aquiring lock"); + emscripten_lock_waitinf_acquire(&mutex); + + emscripten_out("signaler: incrementing globalVar"); + globalVar += 1; + + emscripten_out("signaler: signaling condition"); + emscripten_condvar_signal(&condvar, 1); + + emscripten_out("signaler: done"); + emscripten_lock_release(&mutex); +} + +#ifdef __EMSCRIPTEN_PTHREADS__ +void* waiter_pthread(void* arg) { + waiter_main(); + return NULL; +} +void* signaler_pthread(void* arg) { + signaler_main(); + return NULL; +} +#endif + +int main() { + emscripten_out("in main"); + +#ifdef __EMSCRIPTEN_PTHREADS__ + pthread_t waiter; + pthread_t signaler; + pthread_create(&waiter, NULL, waiter_pthread, NULL); + pthread_create(&signaler, NULL, signaler_pthread, NULL); + pthread_join(waiter, NULL); + pthread_join(signaler, NULL); + emscripten_out("done"); +#else + emscripten_wasm_worker_t waiter = emscripten_malloc_wasm_worker(1024); + emscripten_wasm_worker_post_function_v(waiter, waiter_main); + + emscripten_wasm_worker_t signaler = emscripten_malloc_wasm_worker(1024); + emscripten_wasm_worker_post_function_v(signaler, signaler_main); +#endif +}