Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions src/lib/libatomic.js
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion src/lib/libsigs.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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',
Expand Down
25 changes: 25 additions & 0 deletions system/lib/pthread/emscripten_atomic_wait_suspending.c
Original file line number Diff line number Diff line change
@@ -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 <emscripten/promise.h>
#include <emscripten/atomic.h>
#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;
}
7 changes: 7 additions & 0 deletions system/lib/pthread/threading_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#pragma once

#include <inttypes.h>
#include <pthread.h>
#include <stdbool.h>

Expand Down Expand Up @@ -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_suspending.
intptr_t _emscripten_atomic_wait_promise(volatile void *addr,
uint32_t value,
double maxWaitMilliseconds);
2 changes: 2 additions & 0 deletions tools/maint/gen_sig_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,13 +384,15 @@ def main(args):
'MAX_WEBGL_VERSION': 0,
'BUILD_AS_WORKER': 1,
'LINK_AS_CXX': 1,
'SHARED_MEMORY': 0,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty in the weeds. These to phases of gen_sig_info.py run with use_cxx=True, which doesn't (can't) include musl C internal headers (which don't work in C++ mode).

However, since SHARED_MEMORY defaults to enabled in gen_sig_info we incldue libatomic.js in the build and end up with this error without this change:

$ tools/maint/gen_sig_info.py 
generating signatures ...
 .. {'WASMFS': 1, 'JS_LIBRARIES': [], 'USE_SDL': 0, 'MAX_WEBGL_VERSION': 0, 'BUILD_AS_WORKER': 1, 'LINK_AS_CXX': 1, 'AUTO_JS_LIBRARIES': 0} + None
/tmp/tmpwetk6rye.cpp:351:11: error: use of undeclared identifier '_emscripten_atomic_wait_promise'
  351 |   (void*)&_emscripten_atomic_wait_promise,
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.

Its kind of hard to explain, but the only output of this script is the libsig.js and if that has not changed we can be sure we didn't break the script. i.e. there are no other / subtle breakage that can occur from changing gen_sig_info.py

'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'])
extract_sig_info(sig_info, {'JS_LIBRARIES': ['libembind.js', 'libemval.js'],
'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})
Expand Down
1 change: 1 addition & 0 deletions tools/system_libs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading