Skip to content

Commit dc80f64

Browse files
authored
Enable emscripten_futex API for Wasm Workers (#26325)
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. Depends on: #26309 Fixes: #26314
1 parent 8407826 commit dc80f64

19 files changed

Lines changed: 127 additions & 48 deletions

ChangeLog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ See docs/process.md for more on how version tagging works.
2929
default in #22257, and is no longer used by emscripten itself. It is also
3030
problematic as it injects a global process.on handler. It is easy to replace
3131
with a simple `--pre-js` file for those that require it. (#26326)
32+
- The following APIs are now available in Wasm Workers:
33+
- emscripten_futex_wait
34+
- emscripten_futex_wake
35+
- emscripten_is_main_runtime_thread
36+
- emscripten_is_main_browser_thread
37+
(#26325)
3238
- Several low level emscripten APIs that return success/failure now return the
3339
C `bool` type rather than `int`. For example `emscripten_proxy_sync` and
3440
`emscripten_is_main_runtime_thread`. (#26316)

site/source/docs/api_reference/wasm_workers.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ the middle.
8686
Pthreads and Wasm Workers share several similarities:
8787

8888
* Both can use emscripten_atomic_* Atomics API,
89+
* Both can use emscripten_futex_wait/wake API,
8990
* Both can use GCC __sync_* Atomics API,
9091
* Both can use C11 and C++11 Atomics APIs,
9192
* Both types of threads have a local stack.

src/lib/libwasm_worker.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#error "internal error, feature_matrix should not allow this"
2626
#endif
2727

28+
#endif // ~WASM_WORKERS
29+
2830
{{{
2931
const workerSupportsFutexWait = () => AUDIO_WORKLET ? "!ENVIRONMENT_IS_AUDIO_WORKLET" : '1';
3032
const wasmWorkerJs = `
@@ -59,7 +61,6 @@
5961
}`;
6062
}}}
6163

62-
#endif // ~WASM_WORKERS
6364

6465

6566
addToLibrary({
@@ -342,5 +343,20 @@ if (ENVIRONMENT_IS_WASM_WORKER
342343
else dispatch(-1/*idx*/, 2/*'timed-out'*/);
343344
};
344345
tryAcquireSemaphore();
345-
}
346+
},
347+
348+
#if !PTHREADS
349+
// When pthreads are used we call `__set_thread_state` immediately on worker
350+
// creation. When wasm workers is used without pthreads, we call
351+
// `__set_thread_state` lazily to save code size for programs that don't use
352+
// the threads state.
353+
__do_set_thread_state__deps: ['__set_thread_state'],
354+
__do_set_thread_state: (tb) => {
355+
___set_thread_state(
356+
/*thread_ptr=*/0,
357+
/*is_main_thread=*/!ENVIRONMENT_IS_WORKER,
358+
/*is_runtime_thread=*/!ENVIRONMENT_IS_WASM_WORKER,
359+
/*supports_wait=*/ENVIRONMENT_IS_WORKER && {{{ workerSupportsFutexWait() }}});
360+
},
361+
#endif
346362
});

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/emscripten_thread_state.S

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,12 @@ is_runtime_thread:
1818
.globaltype supports_wait, i32
1919
supports_wait:
2020

21-
.section .text,"",@
21+
#if WASM_WORKERS_ONLY
22+
.globaltype done_init, i32
23+
done_init:
24+
#endif
2225

23-
.globl __get_tp
24-
__get_tp:
25-
.functype __get_tp () -> (PTR)
26-
global.get thread_ptr
27-
end_function
26+
.section .text,"",@
2827

2928
.globl __set_thread_state
3029
__set_thread_state:
@@ -39,23 +38,59 @@ __set_thread_state:
3938
global.set supports_wait
4039
end_function
4140

41+
#if WASM_WORKERS_ONLY
42+
// With Wasm Workers we do lazy initializtion of the thread
43+
// state so that only workers that call these APIs actually
44+
// initializes their state.
45+
.functype __do_set_thread_state () -> ()
46+
47+
lazy_init_thread_state:
48+
.functype lazy_init_thread_state () -> ()
49+
block
50+
global.get done_init
51+
br_if 0
52+
call __do_set_thread_state
53+
i32.const 1
54+
global.set done_init
55+
end_block
56+
end_function
57+
#endif
58+
59+
.globl __get_tp
60+
__get_tp:
61+
.functype __get_tp () -> (PTR)
62+
#if WASM_WORKERS_ONLY
63+
call lazy_init_thread_state
64+
#endif
65+
global.get thread_ptr
66+
end_function
67+
4268
# Semantically the same as testing "!ENVIRONMENT_IS_PTHREAD" in JS
4369
.globl emscripten_is_main_runtime_thread
4470
emscripten_is_main_runtime_thread:
4571
.functype emscripten_is_main_runtime_thread () -> (i32)
72+
#if WASM_WORKERS_ONLY
73+
call lazy_init_thread_state
74+
#endif
4675
global.get is_runtime_thread
4776
end_function
4877

4978
# Semantically the same as testing "!ENVIRONMENT_IS_WORKER" in JS
5079
.globl emscripten_is_main_browser_thread
5180
emscripten_is_main_browser_thread:
5281
.functype emscripten_is_main_browser_thread () -> (i32)
82+
#if WASM_WORKERS_ONLY
83+
call lazy_init_thread_state
84+
#endif
5385
global.get is_main_thread
5486
end_function
5587

5688
# Semantically the same as testing "!ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_AUDIO_WORKLET" in JS
5789
.globl _emscripten_thread_supports_atomics_wait
5890
_emscripten_thread_supports_atomics_wait:
5991
.functype _emscripten_thread_supports_atomics_wait () -> (i32)
92+
#if WASM_WORKERS_ONLY
93+
call lazy_init_thread_state
94+
#endif
6095
global.get supports_wait
6196
end_function

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) {

test/codesize/test_codesize_cxx_ctors1.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
"a.out.js": 19555,
33
"a.out.js.gz": 8102,
44
"a.out.nodebug.wasm": 132828,
5-
"a.out.nodebug.wasm.gz": 49874,
5+
"a.out.nodebug.wasm.gz": 49876,
66
"total": 152383,
7-
"total_gz": 57976,
7+
"total_gz": 57978,
88
"sent": [
99
"__cxa_throw",
1010
"_abort_js",

test/codesize/test_codesize_cxx_ctors2.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
"a.out.js": 19532,
33
"a.out.js.gz": 8087,
44
"a.out.nodebug.wasm": 132248,
5-
"a.out.nodebug.wasm.gz": 49531,
5+
"a.out.nodebug.wasm.gz": 49533,
66
"total": 151780,
7-
"total_gz": 57618,
7+
"total_gz": 57620,
88
"sent": [
99
"__cxa_throw",
1010
"_abort_js",

test/codesize/test_codesize_cxx_except.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
"a.out.js": 23216,
33
"a.out.js.gz": 9081,
44
"a.out.nodebug.wasm": 172758,
5-
"a.out.nodebug.wasm.gz": 57395,
5+
"a.out.nodebug.wasm.gz": 57391,
66
"total": 195974,
7-
"total_gz": 66476,
7+
"total_gz": 66472,
88
"sent": [
99
"__cxa_begin_catch",
1010
"__cxa_end_catch",

test/codesize/test_codesize_cxx_except_wasm.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
"a.out.js": 19366,
33
"a.out.js.gz": 8022,
44
"a.out.nodebug.wasm": 148153,
5-
"a.out.nodebug.wasm.gz": 55275,
5+
"a.out.nodebug.wasm.gz": 55273,
66
"total": 167519,
7-
"total_gz": 63297,
7+
"total_gz": 63295,
88
"sent": [
99
"_abort_js",
1010
"_tzset_js",

0 commit comments

Comments
 (0)