diff options
author | Morten Sørvig <[email protected]> | 2024-12-19 15:05:56 +0100 |
---|---|---|
committer | Morten Sørvig <[email protected]> | 2025-03-03 18:24:43 +0100 |
commit | 9df167a013b6db0957e35d3924e331a145d518b2 (patch) | |
tree | 20b01ca440c181078f5f19baab2df5e0654fed74 /src | |
parent | b80deb26280ad693cd24fe5e723b385bf9ffa15b (diff) |
wasm: introduce qwasmglobal_p.h
Global helpers/utils for Q_OS_WASM.
Move the thread proxying functions to qwasmglobal_p.h,
and update calling code.
qtstweb_p.h now contains C++ wrappers for native web
API only. The proxying functions will be removed from
qeventdispatcher_wasm in a later commit.
Change-Id: I08a56c211b08929750970895b63ca48d4a07a0a1
Reviewed-by: Lorn Potter <[email protected]>
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/corelib/io/qsettings_wasm.cpp | 13 | ||||
-rw-r--r-- | src/corelib/platform/wasm/qstdweb.cpp | 2 | ||||
-rw-r--r-- | src/corelib/platform/wasm/qstdweb_p.h | 42 | ||||
-rw-r--r-- | src/corelib/platform/wasm/qwasmglobal.cpp | 56 | ||||
-rw-r--r-- | src/corelib/platform/wasm/qwasmglobal_p.h | 69 | ||||
-rw-r--r-- | src/corelib/platform/wasm/qwasmsocket.cpp | 13 | ||||
-rw-r--r-- | src/network/access/qnetworkreplywasmimpl.cpp | 4 |
8 files changed, 144 insertions, 56 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index 8d0e60af9b9..68745591d2c 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -1440,6 +1440,7 @@ endif() qt_internal_extend_target(Core CONDITION WASM SOURCES + platform/wasm/qwasmglobal.cpp platform/wasm/qwasmglobal_p.h platform/wasm/qstdweb.cpp platform/wasm/qstdweb_p.h platform/wasm/qwasmsocket.cpp platform/wasm/qwasmsocket_p.h platform/wasm/qwasmsuspendresumecontrol.cpp platform/wasm/qwasmsuspendresumecontrol_p.h diff --git a/src/corelib/io/qsettings_wasm.cpp b/src/corelib/io/qsettings_wasm.cpp index 7d80ff82d37..72045a2d519 100644 --- a/src/corelib/io/qsettings_wasm.cpp +++ b/src/corelib/io/qsettings_wasm.cpp @@ -11,6 +11,7 @@ #endif // QT_NO_QOBJECT #include <QDebug> #include <QtCore/private/qstdweb_p.h> +#include <QtCore/private/qwasmglobal_p.h> #include <QFileInfo> #include <QDir> @@ -109,7 +110,7 @@ void QWasmLocalStorageSettingsPrivate::remove(const QString &key) { const std::string removed = QString(m_keyPrefixes.first() + key).toStdString(); - qstdweb::runTaskOnMainThread<void>([this, &removed, &key]() { + qwasmglobal::runTaskOnMainThread<void>([this, &removed, &key]() { std::vector<std::string> children = { removed }; const int length = val::global("window")["localStorage"]["length"].as<int>(); for (int i = 0; i < length; ++i) { @@ -131,7 +132,7 @@ void QWasmLocalStorageSettingsPrivate::remove(const QString &key) void QWasmLocalStorageSettingsPrivate::set(const QString &key, const QVariant &value) { - qstdweb::runTaskOnMainThread<void>([this, &key, &value]() { + qwasmglobal::runTaskOnMainThread<void>([this, &key, &value]() { const std::string keyString = QString(m_keyPrefixes.first() + key).toStdString(); const std::string valueString = QSettingsPrivate::variantToString(value).toStdString(); val::global("window")["localStorage"].call<void>("setItem", keyString, valueString); @@ -140,7 +141,7 @@ void QWasmLocalStorageSettingsPrivate::set(const QString &key, const QVariant &v std::optional<QVariant> QWasmLocalStorageSettingsPrivate::get(const QString &key) const { - return qstdweb::runTaskOnMainThread<std::optional<QVariant>>( + return qwasmglobal::runTaskOnMainThread<std::optional<QVariant>>( [this, &key]() -> std::optional<QVariant> { for (const auto &prefix : m_keyPrefixes) { const std::string keyString = QString(prefix + key).toStdString(); @@ -160,7 +161,7 @@ std::optional<QVariant> QWasmLocalStorageSettingsPrivate::get(const QString &key QStringList QWasmLocalStorageSettingsPrivate::children(const QString &prefix, ChildSpec spec) const { - return qstdweb::runTaskOnMainThread<QStringList>([this, &prefix, &spec]() -> QStringList { + return qwasmglobal::runTaskOnMainThread<QStringList>([this, &prefix, &spec]() -> QStringList { QSet<QString> nodes; // Loop through all keys on window.localStorage, return Qt keys belonging to // this application, with the correct prefix, and according to ChildSpec. @@ -192,7 +193,7 @@ QStringList QWasmLocalStorageSettingsPrivate::children(const QString &prefix, Ch void QWasmLocalStorageSettingsPrivate::clear() { - qstdweb::runTaskOnMainThread<void>([this]() { + qwasmglobal::runTaskOnMainThread<void>([this]() { // Get all Qt keys from window.localStorage const int length = val::global("window")["localStorage"]["length"].as<int>(); QStringList keys; @@ -347,7 +348,7 @@ QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings:: // Check if cookies are enabled (required for using persistent storage) - const bool cookiesEnabled = qstdweb::runTaskOnMainThread<bool>( + const bool cookiesEnabled = qwasmglobal::runTaskOnMainThread<bool>( []() { return val::global("navigator")["cookieEnabled"].as<bool>(); }); constexpr QLatin1StringView cookiesWarningMessage( diff --git a/src/corelib/platform/wasm/qstdweb.cpp b/src/corelib/platform/wasm/qstdweb.cpp index c51c7e827c2..970e717212d 100644 --- a/src/corelib/platform/wasm/qstdweb.cpp +++ b/src/corelib/platform/wasm/qstdweb.cpp @@ -2,6 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qstdweb_p.h" +#include "qwasmsuspendresumecontrol_p.h" +#include "qwasmglobal_p.h" #include <QtCore/qcoreapplication.h> #include <QtCore/qfile.h> diff --git a/src/corelib/platform/wasm/qstdweb_p.h b/src/corelib/platform/wasm/qstdweb_p.h index 5cb5db1f549..d34b86bce73 100644 --- a/src/corelib/platform/wasm/qstdweb_p.h +++ b/src/corelib/platform/wasm/qstdweb_p.h @@ -290,48 +290,6 @@ namespace qstdweb { bool Q_CORE_EXPORT haveAsyncify(); bool Q_CORE_EXPORT haveJspi(); bool canBlockCallingThread(); - - struct CancellationFlag - { - }; - -#if QT_CONFIG(thread) - template<class T> - T proxyCall(std::function<T()> task, emscripten::ProxyingQueue *queue) - { - T result; - queue->proxySync(emscripten_main_runtime_thread_id(), - [task, result = &result]() { *result = task(); }); - return result; - } - - template<> - inline void proxyCall<void>(std::function<void()> task, emscripten::ProxyingQueue *queue) - { - queue->proxySync(emscripten_main_runtime_thread_id(), task); - } - - template<class T> - T runTaskOnMainThread(std::function<T()> task, emscripten::ProxyingQueue *queue) - { - return emscripten_is_main_runtime_thread() ? task() : proxyCall<T>(std::move(task), queue); - } - - template<class T> - T runTaskOnMainThread(std::function<T()> task) - { - emscripten::ProxyingQueue singleUseQueue; - return runTaskOnMainThread<T>(task, &singleUseQueue); - } - -#else - template<class T> - T runTaskOnMainThread(std::function<T()> task) - { - return task(); - } -#endif // QT_CONFIG(thread) - } QT_END_NAMESPACE diff --git a/src/corelib/platform/wasm/qwasmglobal.cpp b/src/corelib/platform/wasm/qwasmglobal.cpp new file mode 100644 index 00000000000..f80db160f08 --- /dev/null +++ b/src/corelib/platform/wasm/qwasmglobal.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qwasmglobal_p.h" + +namespace qwasmglobal { + +Q_GLOBAL_STATIC(emscripten::ProxyingQueue, proxyingQueue); + +namespace { + void trampoline(void *context) { + + auto async_fn = [](void *context){ + std::function<void(void)> *fn = reinterpret_cast<std::function<void(void)> *>(context); + (*fn)(); + delete fn; + }; + + emscripten_async_call(async_fn, context, 0); + } +} + +void runOnMainThread(std::function<void(void)> fn) +{ +#if QT_CONFIG(thread) + runTaskOnMainThread<void>(fn, proxyingQueue()); +#else + runTaskOnMainThread<void>(fn); +#endif +} + +// Runs a function asynchronously. Main thread only. +void runAsync(std::function<void(void)> fn) +{ + Q_ASSERT(emscripten_is_main_runtime_thread()); + trampoline(new std::function<void(void)>(fn)); +} + +// Runs a function on the main thread. The function always runs asynchronously, +// also if the calling thread is the main thread. +void runOnMainThreadAsync(std::function<void(void)> fn) +{ + void *context = new std::function<void(void)>(fn); +#if QT_CONFIG(thread) + if (!emscripten_is_main_runtime_thread()) { + proxyingQueue()->proxyAsync(emscripten_main_runtime_thread_id(), [context]{ + trampoline(context); + }); + return; + } +#endif + trampoline(context); +} + +} + diff --git a/src/corelib/platform/wasm/qwasmglobal_p.h b/src/corelib/platform/wasm/qwasmglobal_p.h new file mode 100644 index 00000000000..3d80014268d --- /dev/null +++ b/src/corelib/platform/wasm/qwasmglobal_p.h @@ -0,0 +1,69 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QWASMGLOBAL_P_H +#define QWASMGLOBAL_P_H + +#include <emscripten/proxying.h> +#include <emscripten/threading.h> + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +namespace qwasmglobal { + +#if QT_CONFIG(thread) + template<class T> + T proxyCall(std::function<T()> task, emscripten::ProxyingQueue *queue) + { + T result; + queue->proxySync(emscripten_main_runtime_thread_id(), + [task, result = &result]() { *result = task(); }); + return result; + } + + template<> + inline void proxyCall<void>(std::function<void()> task, emscripten::ProxyingQueue *queue) + { + queue->proxySync(emscripten_main_runtime_thread_id(), task); + } + + template<class T> + T runTaskOnMainThread(std::function<T()> task, emscripten::ProxyingQueue *queue) + { + return emscripten_is_main_runtime_thread() ? task() : proxyCall<T>(std::move(task), queue); + } + + template<class T> + T runTaskOnMainThread(std::function<T()> task) + { + emscripten::ProxyingQueue singleUseQueue; + return runTaskOnMainThread<T>(task, &singleUseQueue); + } + +#else + template<class T> + T runTaskOnMainThread(std::function<T()> task) + { + return task(); + } +#endif // QT_CONFIG(thread) + + void runAsync(std::function<void(void)> fn); + void runOnMainThread(std::function<void(void)> fn); + void runOnMainThreadAsync(std::function<void(void)> fn); +} + +QT_END_NAMESPACE + +#endif // QWASMGLOBAL_P_H diff --git a/src/corelib/platform/wasm/qwasmsocket.cpp b/src/corelib/platform/wasm/qwasmsocket.cpp index e7901a54fb9..64af09e9871 100644 --- a/src/corelib/platform/wasm/qwasmsocket.cpp +++ b/src/corelib/platform/wasm/qwasmsocket.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qwasmsocket_p.h" +#include "qwasmglobal_p.h" #include <QtCore/qsocketnotifier.h> #include "emscripten.h" @@ -28,7 +29,7 @@ void QWasmSocket::registerSocketNotifier(QSocketNotifier *notifier) bool wasEmpty = g_socketNotifiers.empty(); g_socketNotifiers.insert({notifier->socket(), notifier}); if (wasEmpty) - QEventDispatcherWasm::runOnMainThread([] { setEmscriptenSocketCallbacks(); }); + qwasmglobal::runOnMainThread([] { setEmscriptenSocketCallbacks(); }); int count; ioctl(notifier->socket(), FIONREAD, &count); @@ -52,7 +53,7 @@ void QWasmSocket::unregisterSocketNotifier(QSocketNotifier *notifier) } if (g_socketNotifiers.empty()) - QEventDispatcherWasm::runOnMainThread([] { clearEmscriptenSocketCallbacks(); }); + qwasmglobal::runOnMainThread([] { clearEmscriptenSocketCallbacks(); }); } void QWasmSocket::clearSocketNotifiers() @@ -104,7 +105,7 @@ void QWasmSocket::socketError(int socket, int err, const char* msg, void *contex // the Qt handler. // It is currently unclear if this problem is caused by code in Qt or in Emscripten, or // if this completely fixes the problem. - QEventDispatcherWasm::runAsync([socket](){ + qwasmglobal::runAsync([socket](){ auto notifiersRange = g_socketNotifiers.equal_range(socket); std::vector<std::pair<int, QSocketNotifier *>> notifiers(notifiersRange.first, notifiersRange.second); for (auto [_, notifier]: notifiers) { @@ -118,7 +119,7 @@ void QWasmSocket::socketOpen(int socket, void *context) { Q_UNUSED(context); - QEventDispatcherWasm::runAsync([socket](){ + qwasmglobal::runAsync([socket](){ auto notifiersRange = g_socketNotifiers.equal_range(socket); std::vector<std::pair<int, QSocketNotifier *>> notifiers(notifiersRange.first, notifiersRange.second); for (auto [_, notifier]: notifiers) { @@ -146,7 +147,7 @@ void QWasmSocket::socketMessage(int socket, void *context) { Q_UNUSED(context); - QEventDispatcherWasm::runAsync([socket](){ + qwasmglobal::runAsync([socket](){ auto notifiersRange = g_socketNotifiers.equal_range(socket); std::vector<std::pair<int, QSocketNotifier *>> notifiers(notifiersRange.first, notifiersRange.second); for (auto [_, notifier]: notifiers) { @@ -167,7 +168,7 @@ void QWasmSocket::socketClose(int socket, void *context) if (socket == 0) return; - QEventDispatcherWasm::runAsync([socket](){ + qwasmglobal::runAsync([socket](){ auto notifiersRange = g_socketNotifiers.equal_range(socket); std::vector<std::pair<int, QSocketNotifier *>> notifiers(notifiersRange.first, notifiersRange.second); for (auto [_, notifier]: notifiers) diff --git a/src/network/access/qnetworkreplywasmimpl.cpp b/src/network/access/qnetworkreplywasmimpl.cpp index 7d225c7e862..1bcf32e643a 100644 --- a/src/network/access/qnetworkreplywasmimpl.cpp +++ b/src/network/access/qnetworkreplywasmimpl.cpp @@ -9,7 +9,7 @@ #include <QtCore/qcoreapplication.h> #include <QtCore/qfileinfo.h> #include <QtCore/qthread.h> -#include <QtCore/private/qeventdispatcher_wasm_p.h> +#include <QtCore/private/qwasmglobal_p.h> #include <QtCore/private/qoffsetstringarray_p.h> #include <QtCore/private/qtools_p.h> @@ -281,7 +281,7 @@ void QNetworkReplyWasmImplPrivate::doSendRequest() } } - QEventDispatcherWasm::runOnMainThread([attr, fetchContext = m_fetchContext]() mutable { + qwasmglobal::runOnMainThread([attr, fetchContext = m_fetchContext]() mutable { std::unique_lock lock{ fetchContext->mutex }; if (fetchContext->state == FetchContext::State::CANCELED) { fetchContext->state = FetchContext::State::FINISHED; |