diff --git a/src/lib/libatomic.js b/src/lib/libatomic.js index cfe0cdea52527..1ea3625244eb1 100644 --- a/src/lib/libatomic.js +++ b/src/lib/libatomic.js @@ -75,11 +75,21 @@ addToLibrary({ }, #if ASYNCIFY - emscripten_atomic_wait_suspending__async: 'auto', - emscripten_atomic_wait_suspending__deps: ['$polyfillWaitAsync', '$atomicWaitStates'], - emscripten_atomic_wait_suspending: async (addr, val, maxWaitMilliseconds) => { + _emscripten_atomic_wait_promise__deps: ['$polyfillWaitAsync', '$atomicWaitStates', '$addPromise'], + _emscripten_atomic_wait_promise: (addr, val, maxWaitMilliseconds) => { var wait = Atomics.waitAsync(HEAP32, {{{ getHeapOffset('addr', 'i32') }}}, val, maxWaitMilliseconds); - return atomicWaitStates.indexOf(await wait.value) + if (wait.async) { + // In the async case return the promise ID. + var chainedPromise = wait.value.then((value) => atomicWaitStates.indexOf(value)); + var id = addPromise(chainedPromise); + return id; + } + // In the synchronous case return the negative result code + return -atomicWaitStates.indexOf(wait.value); + }, +#else + _emscripten_atomic_wait_promise: (addr, val, maxWaitMilliseconds) => { + abort('Please compile your program with async support in order to use asynchronous operations like emscripten_atomic_wait_suspending'); }, #endif diff --git a/src/lib/libsigs.js b/src/lib/libsigs.js index 2e60ffccb6ab0..b26e411a62364 100644 --- a/src/lib/libsigs.js +++ b/src/lib/libsigs.js @@ -314,6 +314,7 @@ sigs = { _embind_register_value_object__sig: 'vpppppp', _embind_register_value_object_field__sig: 'vpppppppppp', _embind_register_void__sig: 'vpp', + _emscripten_atomic_wait_promise__sig: 'ppid', _emscripten_create_audio_worklet__sig: 'viipippp', _emscripten_create_wasm_worker__sig: 'iipip', _emscripten_dlopen_js__sig: 'vpppp', @@ -592,7 +593,6 @@ sigs = { emscripten_atomic_cancel_all_wait_asyncs_at_address__sig: 'ip', emscripten_atomic_cancel_wait_async__sig: 'ii', emscripten_atomic_wait_async__sig: 'ipippd', - emscripten_atomic_wait_suspending__sig: 'ipid', emscripten_atomics_is_lock_free__sig: 'ii', emscripten_audio_context_quantum_size__sig: 'ii', emscripten_audio_context_sample_rate__sig: 'ii', diff --git a/system/lib/pthread/emscripten_atomic_wait_suspending.c b/system/lib/pthread/emscripten_atomic_wait_suspending.c new file mode 100644 index 0000000000000..32e09ddd25ed5 --- /dev/null +++ b/system/lib/pthread/emscripten_atomic_wait_suspending.c @@ -0,0 +1,25 @@ +/* + * 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 +#include +#include "threading_internal.h" + +ATOMICS_WAIT_TOKEN_T emscripten_atomic_wait_suspending(volatile void * _Nonnull addr, + uint32_t value, + double maxWaitMilliseconds) { + intptr_t res = _emscripten_atomic_wait_promise(addr, value, maxWaitMilliseconds); + // A negative value is a synchronous result code. + if (res < 0) { + return (ATOMICS_WAIT_TOKEN_T)-res; + } + // Otherwise a positive value is a promise ID, and we can then `await` using + // ASYNCIFY/JSPI. + em_promise_t promise = (em_promise_t)res; + void* await_result = emscripten_promise_await_unchecked(promise); + return (ATOMICS_WAIT_TOKEN_T)(intptr_t)await_result; +} diff --git a/system/lib/pthread/threading_internal.h b/system/lib/pthread/threading_internal.h index 7803603ccedfa..5b278b133b1b8 100644 --- a/system/lib/pthread/threading_internal.h +++ b/system/lib/pthread/threading_internal.h @@ -7,6 +7,7 @@ #pragma once +#include #include #include @@ -131,3 +132,9 @@ void* _emscripten_init_pthread(void *base, size_t* size, pid_t tid); // __builtin_wasm_memory_atomic_waitXX then they will not be woken by // this method. void _emscripten_thread_notify(pthread_t thread); + +// Internal promise-returning API used to implement +// emscripten_atomic_wait_syspending. +intptr_t _emscripten_atomic_wait_promise(volatile void *addr, + uint32_t value, + double maxWaitMilliseconds); diff --git a/tools/maint/gen_sig_info.py b/tools/maint/gen_sig_info.py index f382447641610..8b04cac54fd5f 100755 --- a/tools/maint/gen_sig_info.py +++ b/tools/maint/gen_sig_info.py @@ -384,6 +384,7 @@ def main(args): 'MAX_WEBGL_VERSION': 0, 'BUILD_AS_WORKER': 1, 'LINK_AS_CXX': 1, + 'SHARED_MEMORY': 0, 'AUTO_JS_LIBRARIES': 0}, cxx=True) extract_sig_info(sig_info, {'AUDIO_WORKLET': 1, 'WASM_WORKERS': 1, 'JS_LIBRARIES': ['libwasm_worker.js', 'libwebaudio.js']}) extract_sig_info(sig_info, {'USE_GLFW': 3}, ['-DGLFW3']) @@ -391,6 +392,7 @@ def main(args): 'USE_SDL': 0, 'MAX_WEBGL_VERSION': 0, 'AUTO_JS_LIBRARIES': 0, + 'SHARED_MEMORY': 0, 'ASYNCIFY': 1}, cxx=True, extra_cflags=['-std=c++20']) extract_sig_info(sig_info, {'LEGACY_GL_EMULATION': 1}, ['-DGLES']) extract_sig_info(sig_info, {'USE_GLFW': 2, 'FULL_ES3': 1, 'MAX_WEBGL_VERSION': 2}) diff --git a/tools/system_libs.py b/tools/system_libs.py index 667dbee0f8920..e18689095156b 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1283,6 +1283,7 @@ def get_files(self): 'emscripten_thread_primitives.c', 'emscripten_futex_wait.c', 'emscripten_futex_wake.c', + 'emscripten_atomic_wait_suspending.c', ]) # These files are in libc directories, but only built in libc_optz.