Skip to content

Commit 73a4b15

Browse files
committed
Enable emscripten_futex API for wasm workers
This involves also including `emscripten_thread_state.S` which provides APIs such as `emscripten_is_main_runtime_thread` and emscripten_is_main_browser_thread` which now also work in Wasm Workers. There is a minor code size hit here of ~80 bytes, but I think its worth it to have these low level APIs available everywhere.
1 parent 7f26ae3 commit 73a4b15

21 files changed

Lines changed: 247 additions & 197 deletions

src/lib/libwasm_worker.js

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,7 @@ addToLibrary({
9393
'$_wasmWorkerRunPostMessage',
9494
'$_wasmWorkerAppendToQueue',
9595
'_emscripten_wasm_worker_initialize',
96-
#if PTHREADS
9796
'__set_thread_state',
98-
#endif
9997
],
10098
$_wasmWorkerInitializeRuntime: () => {
10199
#if ASSERTIONS
@@ -126,11 +124,9 @@ addToLibrary({
126124
#endif
127125
// Run the C side Worker initialization for stack and TLS.
128126
__emscripten_wasm_worker_initialize(wwParams.stackLowestAddress, wwParams.stackSize);
129-
#if PTHREADS
130-
// Record the pthread configuration, and whether this Wasm Worker supports synchronous blocking in emscripten_futex_wait().
127+
// Record low level information. Now all Wasm Workers support synchronous blocking in emscripten_futex_wait().
131128
// (regular Wasm Workers do, AudioWorklets don't)
132129
___set_thread_state(/*thread_ptr=*/0, /*is_main_thread=*/0, /*is_runtime_thread=*/0, /*supports_wait=*/ {{{ workerSupportsFutexWait() }}});
133-
#endif
134130
#if STACK_OVERFLOW_CHECK >= 2
135131
// Fix up stack base. (TLS frame is created at the bottom address end of the stack)
136132
// See https://github.com/emscripten-core/emscripten/issues/16496
@@ -342,5 +338,17 @@ if (ENVIRONMENT_IS_WASM_WORKER
342338
else dispatch(-1/*idx*/, 2/*'timed-out'*/);
343339
};
344340
tryAcquireSemaphore();
345-
}
341+
},
342+
343+
_emscripten_init_main_thread_js__deps: ['__set_thread_state'],
344+
_emscripten_init_main_thread_js: (tb) => {
345+
// Pass the thread address to the native code where they are stored in wasm
346+
// globals which act as a form of TLS. Global constructors trying
347+
// to access this value will read the wrong value, but that is UB anyway.
348+
___set_thread_state(
349+
/*thread_ptr=*/0,
350+
/*is_main_thread=*/!ENVIRONMENT_IS_WORKER,
351+
/*is_runtime_thread=*/1,
352+
/*supports_wait=*/!ENVIRONMENT_IS_WEB);
353+
},
346354
});

src/shell_minimal.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ var ENVIRONMENT_IS_NODE = {{{ nodeDetectionCode() }}};
3939
var ENVIRONMENT_IS_SHELL = !!globalThis.read;
4040
#endif
4141

42-
#if ASSERTIONS || PTHREADS
42+
#if ASSERTIONS || PTHREADS || WASM_WORKERS
4343
#if !ENVIRONMENT_MAY_BE_NODE && !ENVIRONMENT_MAY_BE_SHELL
4444
var ENVIRONMENT_IS_WEB = true
4545
#elif ENVIRONMENT.length == 1

system/include/emscripten/threading.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,13 @@ int emscripten_futex_wake(volatile void/*uint32_t*/ * _Nonnull addr, int count);
4242

4343
// Returns true if the current thread is the thread that hosts the Emscripten
4444
// runtime.
45+
// Returns false on pthreads and Wasm Workers.
4546
bool emscripten_is_main_runtime_thread(void);
4647

4748
// Returns true if the current thread is the main browser thread. In the case
4849
// that the Emscripten module is started in a worker there will be no thread
4950
// for which this returns true.
51+
// Returns false on pthreads and Wasm Workers.
5052
bool emscripten_is_main_browser_thread(void);
5153

5254
// A temporary workaround to issue

system/lib/pthread/library_pthread_stub.c

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ bool emscripten_has_threading_support() { return false; }
2121

2222
int emscripten_num_logical_cores() { return 1; }
2323

24+
#ifndef __EMSCRIPTEN_WASM_WORKERS__
25+
// These low level primites are defined in both pthreads and wasm workers
26+
// builds.
27+
2428
int emscripten_futex_wait(volatile void /*uint32_t*/* addr,
2529
uint32_t val,
2630
double maxWaitMilliseconds) {
@@ -39,10 +43,20 @@ int emscripten_futex_wake(volatile void /*uint32_t*/* addr, int count) {
3943
}
4044

4145
bool emscripten_is_main_runtime_thread() {
42-
// TODO: We probably shouldn't be returning true here in WASM_WORKERS builds.
4346
return true;
4447
}
4548

49+
void __wait(volatile int *addr, volatile int *waiters, int val, int priv) {}
50+
51+
void __lock(void* ptr) {}
52+
53+
void __unlock(void* ptr) {}
54+
55+
void __acquire_ptc() {}
56+
57+
void __release_ptc() {}
58+
#endif
59+
4660
void emscripten_main_thread_process_queued_calls() {
4761
// nop
4862
}
@@ -385,16 +399,6 @@ int sem_destroy(sem_t *sem) {
385399
return 0;
386400
}
387401

388-
void __wait(volatile int *addr, volatile int *waiters, int val, int priv) {}
389-
390-
void __lock(void* ptr) {}
391-
392-
void __unlock(void* ptr) {}
393-
394-
void __acquire_ptc() {}
395-
396-
void __release_ptc() {}
397-
398402
// When pthreads is not enabled, we can't use the Atomics futex api to do
399403
// proper sleeps, so simulate a busy spin wait loop instead.
400404
void emscripten_thread_sleep(double msecs) {

system/lib/wasm_worker/library_wasm_worker.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,12 @@ void emscripten_condvar_signal(emscripten_condvar_t *condvar, int64_t numWaiters
223223
emscripten_atomic_add_u32((void*)condvar, 1);
224224
emscripten_atomic_notify((int*)condvar, numWaitersToSignal);
225225
}
226+
227+
void _emscripten_init_main_thread_js(void* tb);
228+
229+
// See system/lib/README.md for static constructor ordering.
230+
// See corresponding definition in library_pthread.c.
231+
__attribute__((constructor(48)))
232+
void _emscripten_init_main_thread(void) {
233+
_emscripten_init_main_thread_js(NULL);
234+
}

0 commit comments

Comments
 (0)