From 91daa78ddee307d1581990ed02450dad4fb535e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 7 Nov 2025 13:52:07 +0200 Subject: [PATCH 1/5] Add emscripten_queue_microtask() API to enable use case described in this thread: https://github.com/emscripten-core/emscripten/pull/25670#discussion_r2469827161. --- ChangeLog.md | 2 ++ src/lib/libhtml5.js | 6 ++++++ src/lib/libsigs.js | 1 + system/include/emscripten/html5.h | 2 ++ test/emscripten_queue_microtask.c | 25 +++++++++++++++++++++++++ test/test_browser.py | 7 +++++++ 6 files changed, 43 insertions(+) create mode 100644 test/emscripten_queue_microtask.c diff --git a/ChangeLog.md b/ChangeLog.md index 612d47b20afa4..175e829ad94e7 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) 4.0.19 - 11/04/25 ----------------- diff --git a/src/lib/libhtml5.js b/src/lib/libhtml5.js index 0d110367b4fe9..f52d5c011e40e 100644 --- a/src/lib/libhtml5.js +++ b/src/lib/libhtml5.js @@ -2374,6 +2374,12 @@ var LibraryHTML5 = { return requestAnimationFrame(tick); }, + emscripten_queue_microtask: (cb, userData) => { + queueMicrotask(() => { + {{{ 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..5d9db6d575971 100644 --- a/src/lib/libsigs.js +++ b/src/lib/libsigs.js @@ -732,6 +732,7 @@ sigs = { emscripten_promise_resolve__sig: 'vpip', emscripten_promise_then__sig: 'ppppp', emscripten_random__sig: 'f', + emscripten_queue_microtask__sig: 'vp', emscripten_request_animation_frame__sig: 'ipp', emscripten_request_animation_frame_loop__sig: 'vpp', emscripten_request_fullscreen__sig: 'ipi', diff --git a/system/include/emscripten/html5.h b/system/include/emscripten/html5.h index 6fb863e2f77b9..be49788d7c42f 100644 --- a/system/include/emscripten/html5.h +++ b/system/include/emscripten/html5.h @@ -466,6 +466,8 @@ int emscripten_request_animation_frame(bool (*cb)(double time, void *userData), void emscripten_cancel_animation_frame(int requestAnimationFrameId); void emscripten_request_animation_frame_loop(bool (*cb)(double time, void *userData), void *userData); +int emscripten_queue_microtask(void (*cb)(void *userData), void *userData); + double emscripten_date_now(void); double emscripten_performance_now(void); diff --git a/test/emscripten_queue_microtask.c b/test/emscripten_queue_microtask.c new file mode 100644 index 0000000000000..1f2ed693b9d74 --- /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 1686fd3cd9c2e..a15d4e49f3e7d 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -5016,6 +5016,13 @@ def test_emscripten_request_animation_frame_loop(self): def test_request_animation_frame(self): self.btest_exit('test_request_animation_frame.c') + def test_emscripten_queue_microtask(self): + self.btest_exit('emscripten_queue_microtask.c') + + @requires_shared_array_buffer + def test_emscripten_queue_microtask_pthread(self): + self.btest_exit('emscripten_queue_microtask.c', cflags=['-pthread', '-sPROXY_TO_PTHREAD']) + @requires_shared_array_buffer def test_emscripten_set_timeout(self): self.btest_exit('emscripten_set_timeout.c', cflags=['-pthread', '-sPROXY_TO_PTHREAD']) From 5b6c25d4e1cb6affa0cc450a6a5cd8a869e9cac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 7 Nov 2025 18:05:32 +0200 Subject: [PATCH 2/5] fix sig --- src/lib/libsigs.js | 2 +- system/include/emscripten/html5.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/libsigs.js b/src/lib/libsigs.js index 5d9db6d575971..3ad870510f178 100644 --- a/src/lib/libsigs.js +++ b/src/lib/libsigs.js @@ -731,8 +731,8 @@ sigs = { emscripten_promise_race__sig: 'ppp', emscripten_promise_resolve__sig: 'vpip', emscripten_promise_then__sig: 'ppppp', + emscripten_queue_microtask__sig: 'ipp', emscripten_random__sig: 'f', - emscripten_queue_microtask__sig: 'vp', emscripten_request_animation_frame__sig: 'ipp', emscripten_request_animation_frame_loop__sig: 'vpp', emscripten_request_fullscreen__sig: 'ipi', diff --git a/system/include/emscripten/html5.h b/system/include/emscripten/html5.h index be49788d7c42f..8bffacd395ca4 100644 --- a/system/include/emscripten/html5.h +++ b/system/include/emscripten/html5.h @@ -466,7 +466,7 @@ int emscripten_request_animation_frame(bool (*cb)(double time, void *userData), void emscripten_cancel_animation_frame(int requestAnimationFrameId); void emscripten_request_animation_frame_loop(bool (*cb)(double time, void *userData), void *userData); -int emscripten_queue_microtask(void (*cb)(void *userData), void *userData); +void emscripten_queue_microtask(void (*cb)(void *userData), void *userData); double emscripten_date_now(void); double emscripten_performance_now(void); From 27918d7c21b9d052fe1b83142cbe838a84221acd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 8 Nov 2025 13:40:16 +0200 Subject: [PATCH 3/5] review --- src/lib/libhtml5.js | 7 +++++-- test/test_browser.py | 12 ++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/lib/libhtml5.js b/src/lib/libhtml5.js index f52d5c011e40e..d323dc1e38a92 100644 --- a/src/lib/libhtml5.js +++ b/src/lib/libhtml5.js @@ -2374,9 +2374,12 @@ var LibraryHTML5 = { return requestAnimationFrame(tick); }, + emscripten_queue_microtask__deps: ['$callUserCallback'], emscripten_queue_microtask: (cb, userData) => { - queueMicrotask(() => { - {{{ makeDynCall('vp', 'cb') }}}(userData); + {{{ runtimeKeepalivePush(); }}} + return queueMicrotask(() => { + {{{ runtimeKeepalivePop(); }}} + callUserCallback(() => {{{ makeDynCall('vp', 'cb') }}}(userData)); }); }, diff --git a/test/test_browser.py b/test/test_browser.py index a15d4e49f3e7d..963193e24687a 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -5016,12 +5016,12 @@ def test_emscripten_request_animation_frame_loop(self): def test_request_animation_frame(self): self.btest_exit('test_request_animation_frame.c') - def test_emscripten_queue_microtask(self): - self.btest_exit('emscripten_queue_microtask.c') - - @requires_shared_array_buffer - def test_emscripten_queue_microtask_pthread(self): - self.btest_exit('emscripten_queue_microtask.c', cflags=['-pthread', '-sPROXY_TO_PTHREAD']) + @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): From d18fa99c2649c9e12787736d0cb16d7410360c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 8 Nov 2025 13:40:49 +0200 Subject: [PATCH 4/5] fix sig --- src/lib/libsigs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/libsigs.js b/src/lib/libsigs.js index 3ad870510f178..ceaa7c207f1e2 100644 --- a/src/lib/libsigs.js +++ b/src/lib/libsigs.js @@ -731,7 +731,7 @@ sigs = { emscripten_promise_race__sig: 'ppp', emscripten_promise_resolve__sig: 'vpip', emscripten_promise_then__sig: 'ppppp', - emscripten_queue_microtask__sig: 'ipp', + emscripten_queue_microtask__sig: 'vpp', emscripten_random__sig: 'f', emscripten_request_animation_frame__sig: 'ipp', emscripten_request_animation_frame_loop__sig: 'vpp', From f87c2db860f6ee064ac5f0f70617b7bae3986910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 13 Nov 2025 19:21:41 +0200 Subject: [PATCH 5/5] Review --- system/include/emscripten/eventloop.h | 2 ++ system/include/emscripten/html5.h | 2 -- test/emscripten_queue_microtask.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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/system/include/emscripten/html5.h b/system/include/emscripten/html5.h index 8bffacd395ca4..6fb863e2f77b9 100644 --- a/system/include/emscripten/html5.h +++ b/system/include/emscripten/html5.h @@ -466,8 +466,6 @@ int emscripten_request_animation_frame(bool (*cb)(double time, void *userData), void emscripten_cancel_animation_frame(int requestAnimationFrameId); void emscripten_request_animation_frame_loop(bool (*cb)(double time, void *userData), void *userData); -void emscripten_queue_microtask(void (*cb)(void *userData), void *userData); - double emscripten_date_now(void); double emscripten_performance_now(void); diff --git a/test/emscripten_queue_microtask.c b/test/emscripten_queue_microtask.c index 1f2ed693b9d74..8aafa95572d5f 100644 --- a/test/emscripten_queue_microtask.c +++ b/test/emscripten_queue_microtask.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include void cb(void *userData) { printf("cb\n");