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 <lorn.potter@qt.io>
This commit is contained in:
parent
b80deb2628
commit
9df167a013
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
56
src/corelib/platform/wasm/qwasmglobal.cpp
Normal file
56
src/corelib/platform/wasm/qwasmglobal.cpp
Normal file
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
69
src/corelib/platform/wasm/qwasmglobal_p.h
Normal file
69
src/corelib/platform/wasm/qwasmglobal_p.h
Normal file
@ -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
|
@ -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)
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user