From 141f0ca338bc65e3817b6effca84e66206fe56f9 Mon Sep 17 00:00:00 2001 From: Mikolaj Boc Date: Fri, 18 Aug 2023 16:31:54 +0200 Subject: [PATCH] Move runTaskOnMainThread to qstdweb_p.h, use it in WASM dispatcher MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This unifies the approach to running sync tasks (possibly with a return value) on the main thread. Change-Id: I2a05c4f40115a79dbf03c03fa8d8db34124884dc Reviewed-by: MikoĊ‚aj Boc --- src/corelib/kernel/qeventdispatcher_wasm.cpp | 72 ++++++++++---------- src/corelib/kernel/qeventdispatcher_wasm_p.h | 1 - src/corelib/platform/wasm/qstdweb_p.h | 42 ++++++++++++ 3 files changed, 77 insertions(+), 38 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_wasm.cpp b/src/corelib/kernel/qeventdispatcher_wasm.cpp index 0de5c14069..25c707643a 100644 --- a/src/corelib/kernel/qeventdispatcher_wasm.cpp +++ b/src/corelib/kernel/qeventdispatcher_wasm.cpp @@ -16,6 +16,12 @@ using namespace std::chrono_literals; +#if QT_CONFIG(thread) +#define PROXYING_QUEUE_PARAM , &g_proxyingQueue +#else +#define PROXYING_QUEUE_PARAM +#endif // QT_CONFIG(thread) + QT_BEGIN_NAMESPACE // using namespace emscripten; @@ -315,8 +321,10 @@ void QEventDispatcherWasm::registerSocketNotifier(QSocketNotifier *notifier) bool wasEmpty = g_socketNotifiers.empty(); g_socketNotifiers.insert({notifier->socket(), notifier}); - if (wasEmpty) - runOnMainThread([]{ setEmscriptenSocketCallbacks(); }); + if (wasEmpty) { + qstdweb::runTaskOnMainThread([] { setEmscriptenSocketCallbacks(); } + PROXYING_QUEUE_PARAM); + } } void QEventDispatcherWasm::unregisterSocketNotifier(QSocketNotifier *notifier) @@ -331,8 +339,10 @@ void QEventDispatcherWasm::unregisterSocketNotifier(QSocketNotifier *notifier) } } - if (g_socketNotifiers.empty()) - runOnMainThread([]{ clearEmscriptenSocketCallbacks(); }); + if (g_socketNotifiers.empty()) { + qstdweb::runTaskOnMainThread([] { clearEmscriptenSocketCallbacks(); } + PROXYING_QUEUE_PARAM); + } } void QEventDispatcherWasm::registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object) @@ -528,14 +538,16 @@ bool QEventDispatcherWasm::wakeEventDispatcherThread() if (useJspi()) { if (!qt_jspi_can_resume_js()) return false; - runOnMainThread([]{ qt_jspi_resume_js(); }); - return true; + return qstdweb::runTaskOnMainThread([]() { return qt_jspi_resume_js(); } + PROXYING_QUEUE_PARAM); } - if (g_is_asyncify_suspended) { - runOnMainThread([]{ qt_asyncify_resume(); }); - return true; - } - return false; + return g_is_asyncify_suspended + && qstdweb::runTaskOnMainThread( + [] { + qt_asyncify_resume(); + return true; + } + PROXYING_QUEUE_PARAM); } // Process event activation callbacks for the main thread event dispatcher. @@ -620,17 +632,19 @@ void QEventDispatcherWasm::updateNativeTimer() // Update the native timer for this thread/dispatcher. This must be // done on the main thread where we have access to native API. - runOnMainThread([this, maintainNativeTimer]() { - Q_ASSERT(emscripten_is_main_runtime_thread()); + qstdweb::runTaskOnMainThread( + [this, maintainNativeTimer]() { + Q_ASSERT(emscripten_is_main_runtime_thread()); - // "this" may have been deleted, or may be about to be deleted. - // Check if the pointer we have is still a valid event dispatcher, - // and keep the mutex locked while updating the native timer to - // prevent it from being deleted. - LOCK_GUARD(g_staticDataMutex); - if (isValidEventDispatcherPointer(this)) - maintainNativeTimer(); - }); + // "this" may have been deleted, or may be about to be deleted. + // Check if the pointer we have is still a valid event dispatcher, + // and keep the mutex locked while updating the native timer to + // prevent it from being deleted. + LOCK_GUARD(g_staticDataMutex); + if (isValidEventDispatcherPointer(this)) + maintainNativeTimer(); + } + PROXYING_QUEUE_PARAM); } // Static timer activation callback. Must be called on the main thread @@ -896,22 +910,6 @@ void QEventDispatcherWasm::runAsync(std::function fn) trampoline(new std::function(fn)); } -// Runs a function on the main thread. The function runs synchronusly if -// the calling thread is then main thread. -void QEventDispatcherWasm::runOnMainThread(std::function fn) -{ -#if QT_CONFIG(thread) - if (!emscripten_is_main_runtime_thread()) { - void *context = new std::function(fn); - g_proxyingQueue.proxyAsync(g_mainThread, [context]{ - trampoline(context); - }); - return; - } -#endif - fn(); -} - // Runs a function on the main thread. The function always runs asynchronously, // also if the calling thread is the main thread. void QEventDispatcherWasm::runOnMainThreadAsync(std::function fn) diff --git a/src/corelib/kernel/qeventdispatcher_wasm_p.h b/src/corelib/kernel/qeventdispatcher_wasm_p.h index 8a9782a96f..598e15dc6b 100644 --- a/src/corelib/kernel/qeventdispatcher_wasm_p.h +++ b/src/corelib/kernel/qeventdispatcher_wasm_p.h @@ -89,7 +89,6 @@ private: static void run(std::function fn); static void runAsync(std::function fn); - static void runOnMainThread(std::function fn); static void runOnMainThreadAsync(std::function fn); static QEventDispatcherWasm *g_mainThreadEventDispatcher; diff --git a/src/corelib/platform/wasm/qstdweb_p.h b/src/corelib/platform/wasm/qstdweb_p.h index 94b99bb0d7..42e6a22381 100644 --- a/src/corelib/platform/wasm/qstdweb_p.h +++ b/src/corelib/platform/wasm/qstdweb_p.h @@ -28,6 +28,11 @@ #include #include +#if QT_CONFIG(thread) +#include +#include +#endif // #if QT_CONFIG(thread) + QT_BEGIN_NAMESPACE class QMimeData; @@ -218,6 +223,43 @@ namespace qstdweb { Q_CORE_EXPORT std::shared_ptr readDataTransfer(emscripten::val webObject, std::function imageReader, std::function)> onDone); + +#if QT_CONFIG(thread) + template + T proxyCall(std::function task, emscripten::ProxyingQueue *queue) + { + T result; + queue->proxySync(emscripten_main_browser_thread_id(), + [task, result = &result]() { *result = task(); }); + return result; + } + + template<> + inline void proxyCall(std::function task, emscripten::ProxyingQueue *queue) + { + queue->proxySync(emscripten_main_browser_thread_id(), task); + } + + template + T runTaskOnMainThread(std::function task, emscripten::ProxyingQueue *queue) + { + return emscripten_is_main_runtime_thread() ? task() : proxyCall(std::move(task), queue); + } + + template + T runTaskOnMainThread(std::function task) + { + emscripten::ProxyingQueue singleUseQueue; + return runTaskOnMainThread(task, &singleUseQueue); + } + +#else + template + T runTaskOnMainThread(std::function task) + { + return task(); + } +#endif // QT_CONFIG(thread) } QT_END_NAMESPACE