diff --git a/ChangeLog.md b/ChangeLog.md index 4d2b8ef7c989e..fbfb3bd320ca8 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,8 @@ See docs/process.md for more on how version tagging works. 4.0.20 (in development) ----------------------- +- Added new `emscripten_queue_microtask()` API to call the JS `queueMicrotask()` + function. (#25741) - Embind now requires C++17 or newer. See #24850. 4.0.19 - 11/04/25 diff --git a/src/lib/libhtml5.js b/src/lib/libhtml5.js index 6c28e9b5471f7..a0f7524b02e04 100644 --- a/src/lib/libhtml5.js +++ b/src/lib/libhtml5.js @@ -2335,6 +2335,15 @@ var LibraryHTML5 = { return requestAnimationFrame(tick); }, + emscripten_queue_microtask__deps: ['$callUserCallback'], + emscripten_queue_microtask: (cb, userData) => { + {{{ runtimeKeepalivePush(); }}} + return queueMicrotask(() => { + {{{ runtimeKeepalivePop(); }}} + callUserCallback(() => {{{ makeDynCall('vp', 'cb') }}}(userData)); + }); + }, + emscripten_get_device_pixel_ratio__proxy: 'sync', emscripten_get_device_pixel_ratio: () => { #if ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL diff --git a/src/lib/libsigs.js b/src/lib/libsigs.js index e2b5f43371de6..ceaa7c207f1e2 100644 --- a/src/lib/libsigs.js +++ b/src/lib/libsigs.js @@ -731,6 +731,7 @@ sigs = { emscripten_promise_race__sig: 'ppp', emscripten_promise_resolve__sig: 'vpip', emscripten_promise_then__sig: 'ppppp', + emscripten_queue_microtask__sig: 'vpp', emscripten_random__sig: 'f', emscripten_request_animation_frame__sig: 'ipp', emscripten_request_animation_frame_loop__sig: 'vpp', diff --git a/system/include/emscripten/eventloop.h b/system/include/emscripten/eventloop.h index 4f706f9acf63b..67a413d0835a0 100644 --- a/system/include/emscripten/eventloop.h +++ b/system/include/emscripten/eventloop.h @@ -26,6 +26,8 @@ void emscripten_set_immediate_loop(bool (*cb)(void *user_data), void *user_data) int emscripten_set_interval(void (*cb)(void *user_data) __attribute__((nonnull)), double interval_ms, void *user_data); void emscripten_clear_interval(int id); +void emscripten_queue_microtask(void (*cb)(void *userData), void *userData); + void emscripten_runtime_keepalive_push(void); void emscripten_runtime_keepalive_pop(void); bool emscripten_runtime_keepalive_check(void); diff --git a/test/emscripten_queue_microtask.c b/test/emscripten_queue_microtask.c new file mode 100644 index 0000000000000..8aafa95572d5f --- /dev/null +++ b/test/emscripten_queue_microtask.c @@ -0,0 +1,25 @@ +/* + * Copyright 2025 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. + */ + +// Test emscripten_queue_microtask() behavior + +#include +#include +#include +#include + +void cb(void *userData) { + printf("cb\n"); + assert(userData == (void*)42); + emscripten_force_exit(0); +} + +int main() { + emscripten_queue_microtask(cb, (void*)42); + emscripten_exit_with_live_runtime(); + return 99; // We won't reach here, but return non-zero value to guard against refactors that might exit() with this value. +} diff --git a/test/test_browser.py b/test/test_browser.py index 43ca990a7d1f1..f7ad76d17156a 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -5024,6 +5024,13 @@ def test_emscripten_request_animation_frame_loop(self): def test_request_animation_frame(self): self.btest_exit('test_request_animation_frame.c') + @parameterized({ + '': ([],), + 'proxy_to_pthread': (['-pthread', '-sPROXY_TO_PTHREAD'],), + }) + def test_emscripten_queue_microtask(self, flags): + self.btest_exit('emscripten_queue_microtask.c', cflags=cflags) + @requires_shared_array_buffer def test_emscripten_set_timeout(self): self.btest_exit('emscripten_set_timeout.c', cflags=['-pthread', '-sPROXY_TO_PTHREAD'])