From 39f7efa12ba7c8a4dd76ed5d992f0829399d57d5 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Mon, 10 Apr 2023 15:03:50 -0700 Subject: [PATCH 1/2] Implement `emscripten_promise_race` in promise.h This function propagates the result of its first input promise to settle, whether it is fulfilled or rejected. --- src/library_promise.js | 15 +++++++++++ system/include/emscripten/promise.h | 8 ++++++ test/core/test_promise.c | 41 ++++++++++++++++++++++++++++- test/core/test_promise.out | 3 +++ 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/library_promise.js b/src/library_promise.js index b2d6aa757d49b..340948b2e43d1 100644 --- a/src/library_promise.js +++ b/src/library_promise.js @@ -237,6 +237,21 @@ mergeInto(LibraryManager.library, { }); #if RUNTIME_DEBUG dbg('create: ' + id); +#endif + return id; + }, + + emscripten_promise_race__deps: ['$promiseMap', '$idsToPromises'], + emscripten_promise_race: function(idBuf, size) { + var promises = idsToPromises(idBuf, size); +#if RUNTIME_DEBUG + dbg('emscripten_promise_race: ' + promises); +#endif + var id = promiseMap.allocate({ + promise: Promise.race(promises) + }); +#if RUNTIME_DEBUG + dbg('create: ' + id); #endif return id; } diff --git a/system/include/emscripten/promise.h b/system/include/emscripten/promise.h index 5168126e5079b..d132455cf3f12 100644 --- a/system/include/emscripten/promise.h +++ b/system/include/emscripten/promise.h @@ -127,6 +127,14 @@ __attribute__((warn_unused_result)) em_promise_t emscripten_promise_all_settled( __attribute__((warn_unused_result)) em_promise_t emscripten_promise_any( em_promise_t* promises, void** errors, size_t num_promises); +// Call Promise.race to create and return a new promise that settles once any of +// the `num_promises` input promises passed in `promises` has been settled. If +// the first input promise to settle is fulfilled, the resulting promise is +// fulfilled with the same value. Otherwise, if the first input promise to +// settle is rejected, the resulting promise is rejected with the same reason. +__attribute__((warn_unused_result)) em_promise_t +emscripten_promise_race(em_promise_t* promises, size_t num_promises); + #ifdef __cplusplus } #endif diff --git a/test/core/test_promise.c b/test/core/test_promise.c index dabe918f7a11c..3a19875acb052 100644 --- a/test/core/test_promise.c +++ b/test/core/test_promise.c @@ -462,6 +462,42 @@ static em_promise_result_t test_any(void** result, void* data, void* value) { return EM_PROMISE_MATCH_RELEASE; } +static em_promise_result_t test_race(void** result, void* data, void* value) { + emscripten_console_log("test_race"); + assert(data == (void*)7); + + em_promise_t in[2] = {emscripten_promise_create(), + emscripten_promise_create()}; + em_promise_t fulfill = emscripten_promise_race(in, 2); + em_promise_t fulfill_checked = + emscripten_promise_then(fulfill, expect_success, fail, NULL); + emscripten_promise_destroy(fulfill); + emscripten_promise_resolve(in[1], EM_PROMISE_FULFILL, (void*)42); + emscripten_promise_resolve(in[0], EM_PROMISE_REJECT, NULL); + emscripten_promise_destroy(in[0]); + emscripten_promise_destroy(in[1]); + + in[0] = emscripten_promise_create(); + in[1] = emscripten_promise_create(); + em_promise_t reject = emscripten_promise_race(in, 2); + em_promise_t reject_checked = + emscripten_promise_then(reject, fail, expect_error, NULL); + emscripten_promise_destroy(reject); + emscripten_promise_resolve(in[0], EM_PROMISE_REJECT, (void*)42); + emscripten_promise_resolve(in[1], EM_PROMISE_FULFILL, NULL); + emscripten_promise_destroy(in[0]); + emscripten_promise_destroy(in[1]); + + em_promise_t to_finish[2] = {fulfill_checked, reject_checked}; + em_promise_t finish_test_race = emscripten_promise_all(to_finish, NULL, 0); + + emscripten_promise_destroy(fulfill_checked); + emscripten_promise_destroy(reject_checked); + + *result = finish_test_race; + return EM_PROMISE_MATCH_RELEASE; +} + static em_promise_result_t finish(void** result, void* data, void* value) { emscripten_console_logf("finish"); @@ -509,8 +545,10 @@ int main() { em_promise_t test5 = emscripten_promise_then(test4, test_all_settled, fail, (void*)5); em_promise_t test6 = emscripten_promise_then(test5, test_any, fail, (void*)6); + em_promise_t test7 = + emscripten_promise_then(test6, test_race, fail, (void*)7); em_promise_t assert_stack = - emscripten_promise_then(test6, check_stack, fail, NULL); + emscripten_promise_then(test7, check_stack, fail, NULL); em_promise_t end = emscripten_promise_then(assert_stack, finish, fail, NULL); emscripten_promise_resolve(start, EM_PROMISE_FULFILL, NULL); @@ -523,6 +561,7 @@ int main() { emscripten_promise_destroy(test4); emscripten_promise_destroy(test5); emscripten_promise_destroy(test6); + emscripten_promise_destroy(test7); emscripten_promise_destroy(assert_stack); emscripten_promise_destroy(end); diff --git a/test/core/test_promise.out b/test/core/test_promise.out index f9db8cc4f22e1..84f57b62633e2 100644 --- a/test/core/test_promise.out +++ b/test/core/test_promise.out @@ -28,4 +28,7 @@ promise_any reasons: 42 43 44 +test_race +expected success: 42 +expected error: 42 finish From c03da663e7f3d2d8092edde623339efb6aa9a332 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Mon, 10 Apr 2023 15:09:42 -0700 Subject: [PATCH 2/2] update library sig file --- src/library_sigs.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/library_sigs.js b/src/library_sigs.js index d46b1c3d1e406..593db24837ccf 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -540,6 +540,7 @@ sigs = { emscripten_promise_any__sig: 'pppp', emscripten_promise_create__sig: 'p', emscripten_promise_destroy__sig: 'vp', + emscripten_promise_race__sig: 'ppp', emscripten_promise_resolve__sig: 'vpip', emscripten_promise_then__sig: 'ppppp', emscripten_random__sig: 'f',