summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmake/QtWasmHelpers.cmake6
-rw-r--r--mkspecs/wasm-emscripten/qmake.conf6
-rw-r--r--src/corelib/kernel/qeventdispatcher_wasm.cpp64
-rw-r--r--tests/manual/wasm/eventloop/asyncify_exec/CMakeLists.txt3
-rw-r--r--tests/manual/wasm/eventloop/asyncify_exec/main.cpp10
5 files changed, 48 insertions, 41 deletions
diff --git a/cmake/QtWasmHelpers.cmake b/cmake/QtWasmHelpers.cmake
index 08e8d97349..c41de308af 100644
--- a/cmake/QtWasmHelpers.cmake
+++ b/cmake/QtWasmHelpers.cmake
@@ -75,9 +75,13 @@ function (qt_internal_setup_wasm_target_properties wasmTarget)
set(QT_CFLAGS_OPTIMIZE_DEBUG "-Os" CACHE STRING INTERNAL FORCE)
set(QT_FEATURE_optimize_debug ON CACHE BOOL INTERNAL FORCE)
- target_link_options("${wasmTarget}" INTERFACE "SHELL:-s ASYNCIFY" "-Os" "-s" "ASYNCIFY_IMPORTS=[qt_asyncify_suspend_js, qt_asyncify_resume_js]")
+ target_link_options("${wasmTarget}" INTERFACE "SHELL:-s ASYNCIFY" "-Os")
target_compile_definitions("${wasmTarget}" INTERFACE QT_HAVE_EMSCRIPTEN_ASYNCIFY)
endif()
+
+ # Set ASYNCIFY_IMPORTS unconditionally in order to support enabling asyncify at link time.
+ target_link_options("${wasmTarget}" INTERFACE "SHELL:-sASYNCIFY_IMPORTS=qt_asyncify_suspend_js,qt_asyncify_resume_js")
+
endfunction()
function(qt_internal_wasm_add_finalizers target)
diff --git a/mkspecs/wasm-emscripten/qmake.conf b/mkspecs/wasm-emscripten/qmake.conf
index 648246b268..6bb99d49b6 100644
--- a/mkspecs/wasm-emscripten/qmake.conf
+++ b/mkspecs/wasm-emscripten/qmake.conf
@@ -22,12 +22,12 @@ load(emcc_ver)
# (with "wasm validation error: too many locals" type errors) if optimizations
# are omitted. Enable optimizations also for debug builds.
QMAKE_LFLAGS_DEBUG += -Os
-
- # Declare all async functions
- QMAKE_LFLAGS += -s \'ASYNCIFY_IMPORTS=[\"qt_asyncify_suspend_js\", \"qt_asyncify_resume_js\", \"emscripten_sleep\"]\'
}
}
+# Declare async functions
+QMAKE_LFLAGS += -s \'ASYNCIFY_IMPORTS=qt_asyncify_suspend_js,qt_asyncify_resume_js\'
+
EMCC_COMMON_LFLAGS += \
-s WASM=1 \
-s MAX_WEBGL_VERSION=2 \
diff --git a/src/corelib/kernel/qeventdispatcher_wasm.cpp b/src/corelib/kernel/qeventdispatcher_wasm.cpp
index 2363d5a79b..82c960cebb 100644
--- a/src/corelib/kernel/qeventdispatcher_wasm.cpp
+++ b/src/corelib/kernel/qeventdispatcher_wasm.cpp
@@ -26,14 +26,16 @@ Q_LOGGING_CATEGORY(lcEventDispatcherTimers, "qt.eventdispatcher.timers");
#define LOCK_GUARD(M)
#endif
-#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY
-
// Emscripten asyncify currently supports one level of suspend -
// recursion is not permitted. We track the suspend state here
// on order to fail (more) gracefully, but we can of course only
// track Qts own usage of asyncify.
static bool g_is_asyncify_suspended = false;
+EM_JS(bool, qt_have_asyncify_js, (), {
+ return typeof Asyncify != "undefined";
+});
+
EM_JS(void, qt_asyncify_suspend_js, (), {
let sleepFn = (wakeUp) => {
Module.qtAsyncifyWakeUp = wakeUp;
@@ -52,6 +54,15 @@ EM_JS(void, qt_asyncify_resume_js, (), {
setTimeout(wakeUp);
});
+// Returns true if asyncify is available.
+bool qt_have_asyncify()
+{
+ static bool have_asyncify = []{
+ return qt_have_asyncify_js();
+ }();
+ return have_asyncify;
+}
+
// Suspends the main thread until qt_asyncify_resume() is called. Returns
// false immediately if Qt has already suspended the main thread (recursive
// suspend is not supported by Emscripten). Returns true (after resuming),
@@ -76,8 +87,6 @@ bool qt_asyncify_resume()
return true;
}
-#endif // QT_HAVE_EMSCRIPTEN_ASYNCIFY
-
Q_CONSTINIT QEventDispatcherWasm *QEventDispatcherWasm::g_mainThreadEventDispatcher = nullptr;
#if QT_CONFIG(thread)
Q_CONSTINIT QVector<QEventDispatcherWasm *> QEventDispatcherWasm::g_secondaryThreadEventDispatchers;
@@ -359,16 +368,15 @@ void QEventDispatcherWasm::handleApplicationExec()
void QEventDispatcherWasm::handleDialogExec()
{
-#ifndef QT_HAVE_EMSCRIPTEN_ASYNCIFY
- qWarning() << "Warning: dialog exec() is not supported on Qt for WebAssembly in this"
- << "configuration. Please use show() instead, or enable experimental support"
- << "for asyncify.\n"
- << "When using exec() (without asyncify) the dialog will show, the user can interact"
- << "with it and the appropriate signals will be emitted on close. However, the"
- << "exec() call never returns, stack content at the time of the exec() call"
- << "is leaked, and the exec() call may interfere with input event processing";
- emscripten_sleep(1); // This call never returns
-#endif
+ if (!qt_have_asyncify()) {
+ qWarning() << "Warning: dialog exec() is not supported on Qt for WebAssembly in this"
+ << "configuration. Please use show() instead, or enable experimental support"
+ << "for asyncify.\n"
+ << "When using exec() (without asyncify) the dialog will show, the user can interact"
+ << "exec() call never returns, stack content at the time of the exec() call"
+ << "is leaked, and the exec() call may interfere with input event processing";
+ emscripten_sleep(1); // This call never returns
+ }
// For the asyncify case we do nothing here and wait for events in wait()
}
@@ -393,20 +401,20 @@ bool QEventDispatcherWasm::wait(int timeout)
#endif
Q_ASSERT(emscripten_is_main_runtime_thread());
Q_ASSERT(isMainThreadEventDispatcher());
-#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY
- if (timeout > 0)
- qWarning() << "QEventDispatcherWasm asyncify wait with timeout is not supported; timeout will be ignored"; // FIXME
-
- bool didSuspend = qt_asyncify_suspend();
- if (!didSuspend) {
- qWarning("QEventDispatcherWasm: current thread is already suspended; could not asyncify wait for events");
- return false;
+ if (qt_have_asyncify()) {
+ if (timeout > 0)
+ qWarning() << "QEventDispatcherWasm asyncify wait with timeout is not supported; timeout will be ignored"; // FIXME
+
+ bool didSuspend = qt_asyncify_suspend();
+ if (!didSuspend) {
+ qWarning("QEventDispatcherWasm: current thread is already suspended; could not asyncify wait for events");
+ return false;
+ }
+ return true;
+ } else {
+ qWarning("QEventLoop::WaitForMoreEvents is not supported on the main thread without asyncify");
+ Q_UNUSED(timeout);
}
- return true;
-#else
- qWarning("QEventLoop::WaitForMoreEvents is not supported on the main thread without asyncify");
- Q_UNUSED(timeout);
-#endif
return false;
}
@@ -424,12 +432,10 @@ bool QEventDispatcherWasm::wakeEventDispatcherThread()
}
#endif
Q_ASSERT(isMainThreadEventDispatcher());
-#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY
if (g_is_asyncify_suspended) {
runOnMainThread([]{ qt_asyncify_resume(); });
return true;
}
-#endif
return false;
}
diff --git a/tests/manual/wasm/eventloop/asyncify_exec/CMakeLists.txt b/tests/manual/wasm/eventloop/asyncify_exec/CMakeLists.txt
index f8328660b2..28825e38a0 100644
--- a/tests/manual/wasm/eventloop/asyncify_exec/CMakeLists.txt
+++ b/tests/manual/wasm/eventloop/asyncify_exec/CMakeLists.txt
@@ -7,3 +7,6 @@ qt_internal_add_manual_test(asyncify_exec
LIBRARIES
Qt::Core
)
+
+# Enable asyncify for this test. Also enable optimizations in order to reduce the binary size.
+target_link_options(asyncify_exec PUBLIC -sASYNCIFY -Os)
diff --git a/tests/manual/wasm/eventloop/asyncify_exec/main.cpp b/tests/manual/wasm/eventloop/asyncify_exec/main.cpp
index c3a827ac11..ab3018c12e 100644
--- a/tests/manual/wasm/eventloop/asyncify_exec/main.cpp
+++ b/tests/manual/wasm/eventloop/asyncify_exec/main.cpp
@@ -2,14 +2,12 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtCore>
-// This test shows how to asyncify enables blocking
-// the main thread on QEventLoop::exec(), while event
-// provessing continues.
+// This test shows how to use asyncify to enable blocking the main
+// thread on QEventLoop::exec(), while event processing continues.
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
-#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY
QTimer::singleShot(1000, []() {
QEventLoop loop;
@@ -22,10 +20,6 @@ int main(int argc, char **argv)
loop.exec();
qDebug() << "Returned from QEventLoop::exec()";
});
-#else
- qDebug() << "This test requires Emscripten asyncify. To enable,"
- << "configure Qt with -device-option QT_EMSCRIPTEN_ASYNCIFY=1";
-#endif
app.exec();
}