Skip to content

Commit 62d7153

Browse files
authored
Fix Wasm Workers calling emscripten_futex_wait() when building with pthreads support enabled. Fixes #21549. (#21618)
Would benefit from a test, I'll look into this shortly.
1 parent c83c291 commit 62d7153

File tree

4 files changed

+55
-3
lines changed

4 files changed

+55
-3
lines changed

src/library_wasm_worker.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@
3232
#error "-sPROXY_TO_WORKER is not supported with -sWASM_WORKERS"
3333
#endif
3434

35+
{{{
36+
globalThis.workerSupportsFutexWait = () => AUDIO_WORKLET ? "typeof AudioWorkletGlobalScope === 'undefined'" : '1';
37+
null;
38+
}}}
39+
3540
#endif // ~WASM_WORKERS
3641

3742

@@ -95,8 +100,9 @@ addToLibrary({
95100
// Run the C side Worker initialization for stack and TLS.
96101
__emscripten_wasm_worker_initialize(m['sb'], m['sz']);
97102
#if PTHREADS
98-
// Record that this Wasm Worker supports synchronous blocking in emscripten_futex_wake().
99-
___set_thread_state(/*thread_ptr=*/0, /*is_main_thread=*/0, /*is_runtime_thread=*/0, /*supports_wait=*/0);
103+
// Record the pthread configuration, and whether this Wasm Worker supports synchronous blocking in emscripten_futex_wait().
104+
// (regular Wasm Workers do, AudioWorklets don't)
105+
___set_thread_state(/*thread_ptr=*/0, /*is_main_thread=*/0, /*is_runtime_thread=*/0, /*supports_wait=*/ {{{ workerSupportsFutexWait() }}});
100106
#endif
101107
#if STACK_OVERFLOW_CHECK >= 2
102108
// Fix up stack base. (TLS frame is created at the bottom address end of the stack)

system/lib/pthread/emscripten_futex_wait.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ static int futex_wait_main_browser_thread(volatile void* addr,
2121
uint32_t val,
2222
double timeout) {
2323
// Atomics.wait is not available in the main browser thread, so simulate it
24-
// via busy spinning.
24+
// via busy spinning. Only the main browser thread is allowed to call into
25+
// this function. It is not thread-safe to be called from any other thread.
26+
assert(emscripten_is_main_browser_thread());
27+
2528
double now = emscripten_get_now();
2629
double end = now + timeout;
2730

test/test_browser.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4946,6 +4946,14 @@ def test_wasm_worker_hello_wasm2js(self):
49464946
def test_wasm_worker_embedded(self):
49474947
self.btest('wasm_worker/hello_wasm_worker.c', expected='0', args=['-sWASM_WORKERS=2'])
49484948

4949+
# Tests that it is possible to call emscripten_futex_wait() in Wasm Workers.
4950+
@parameterized({
4951+
'': ([],),
4952+
'pthread': (['-pthread'],),
4953+
})
4954+
def test_wasm_worker_futex_wait(self, args):
4955+
self.btest('wasm_worker/wasm_worker_futex_wait.c', expected='0', args=['-sWASM_WORKERS=1', '-sASSERTIONS'] + args)
4956+
49494957
# Tests Wasm Worker thread stack setup
49504958
@also_with_minimal_runtime
49514959
def test_wasm_worker_thread_stack(self):
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Test that emscripten_futex_wait() works in a Wasm Worker.
2+
3+
#include <emscripten.h>
4+
#include <emscripten/console.h>
5+
#include <emscripten/threading.h>
6+
#include <emscripten/wasm_worker.h>
7+
#include <limits.h>
8+
#include <stdio.h>
9+
#include <math.h>
10+
11+
_Atomic uint32_t futex_value = 0;
12+
13+
void wake_worker_after_delay(void *user_data) {
14+
futex_value = 1;
15+
emscripten_futex_wake(&futex_value, INT_MAX);
16+
}
17+
18+
void wake_worker() {
19+
printf("Waking worker thread from futex wait.\n");
20+
emscripten_set_timeout(wake_worker_after_delay, 500, 0);
21+
}
22+
23+
void worker_main() {
24+
printf("Worker sleeping for futex wait.\n");
25+
emscripten_wasm_worker_post_function_v(0, wake_worker);
26+
int rc = emscripten_futex_wait(&futex_value, 0, INFINITY);
27+
printf("emscripten_futex_wait returned with code %d.\n", rc);
28+
#ifdef REPORT_RESULT
29+
REPORT_RESULT(rc);
30+
#endif
31+
}
32+
33+
int main() {
34+
emscripten_wasm_worker_post_function_v(emscripten_malloc_wasm_worker(1024), worker_main);
35+
}

0 commit comments

Comments
 (0)