From 129ab89c5d02d03d2e1b86c8ea51b97c9f64e57c Mon Sep 17 00:00:00 2001 From: Piotr Wiercinski Date: Wed, 27 Dec 2023 12:34:00 +0100 Subject: [PATCH] wasm: Fix handling of promise pool in WebPromiseManager Promises are registered upon entry to the pool and unregistered upon exit. If all promises are in a 'pending' state, new promises can't be processed. Upon completion of a registered promise, it is unregistered, allowing space for a new promise. The code path responsible for unregistering promises when they resolve runs each time a promise's callback is called. Unfortunately, there's no guarantee that the callback will be invoked upon the promise's resolution. For instance, promises registered with only a 'catch' callback may never be triggered when the promise resolves correctly. This commit ensures that a final callback is always registered, even if the user did not provide one. This guarantees that promises are always unregistered upon resolution Fixes: QTBUG-118161 Pick-to: 6.5 Change-Id: Ifea93d692464a6ef40c4bcad60f840ca0cb650c9 Reviewed-by: Lorn Potter (cherry picked from commit 1e6841245dca3bda5dee050fc841c7129142dd9f) Reviewed-by: Qt Cherry-pick Bot (cherry picked from commit a625d521f70c4897ba4ebeb7f1c7195e571290fb) --- src/corelib/platform/wasm/qstdweb.cpp | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/corelib/platform/wasm/qstdweb.cpp b/src/corelib/platform/wasm/qstdweb.cpp index 374e6b25d92..1f148e80696 100644 --- a/src/corelib/platform/wasm/qstdweb.cpp +++ b/src/corelib/platform/wasm/qstdweb.cpp @@ -136,11 +136,12 @@ public: "catch", emscripten::val::module_property(thunkName(CallbackType::Catch, id()).data())); } - if (callbacks.finallyFunc) { - target = target.call( - "finally", - emscripten::val::module_property(thunkName(CallbackType::Finally, id()).data())); - } + // Guarantee the invocation of at least one callback by always + // registering 'finally'. This is required by WebPromiseManager + // design + target = target.call( + "finally", emscripten::val::module_property( + thunkName(CallbackType::Finally, id()).data())); } private: @@ -321,25 +322,21 @@ void WebPromiseManager::promiseThunkCallback(int context, CallbackType type, ems auto* promiseState = &m_promiseRegistry[context]; auto* callbacks = &promiseState->callbacks; - bool expectingOtherCallbacks; switch (type) { case CallbackType::Then: callbacks->thenFunc(result); - // At this point, if there is no finally function, we are sure that the Catch callback won't be issued. - expectingOtherCallbacks = !!callbacks->finallyFunc; break; case CallbackType::Catch: callbacks->catchFunc(result); - expectingOtherCallbacks = !!callbacks->finallyFunc; break; case CallbackType::Finally: - callbacks->finallyFunc(); - expectingOtherCallbacks = false; + // Final callback may be empty, used solely for promise unregistration + if (callbacks->finallyFunc) { + callbacks->finallyFunc(); + } + unregisterPromise(context); break; - } - - if (!expectingOtherCallbacks) - unregisterPromise(context); + } } void WebPromiseManager::registerPromise(