wasm: include asyncify support unconditionally
Emscripten's option for enabling asyncify (-sASYNCIFY) is a link-time option, which means there is no requirement to have a separate asyncify build, at least for static builds. Replace the current QT_HAVE_EMSCRIPTEN_ASYNCIFY compile-time option with a run-time option which checks if the asyncify API is available. Keep support for configuring with "-device-option QT_EMSCRIPTEN_ASYNCIFY=1" for backwards compatibility and for the use case where want asyncify support to be on by default for a given Qt build. Enable asyncify for the asyncify_exec example. Pick-to: 6.4 Change-Id: I301fd7e2d3c0367532c886f4e34b23e1093646ad Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
parent
238e90cd58
commit
f347682fd5
@ -75,9 +75,13 @@ function (qt_internal_setup_wasm_target_properties wasmTarget)
|
|||||||
set(QT_CFLAGS_OPTIMIZE_DEBUG "-Os" CACHE STRING INTERNAL FORCE)
|
set(QT_CFLAGS_OPTIMIZE_DEBUG "-Os" CACHE STRING INTERNAL FORCE)
|
||||||
set(QT_FEATURE_optimize_debug ON CACHE BOOL 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)
|
target_compile_definitions("${wasmTarget}" INTERFACE QT_HAVE_EMSCRIPTEN_ASYNCIFY)
|
||||||
endif()
|
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()
|
endfunction()
|
||||||
|
|
||||||
function(qt_internal_wasm_add_finalizers target)
|
function(qt_internal_wasm_add_finalizers target)
|
||||||
|
@ -22,11 +22,11 @@ load(emcc_ver)
|
|||||||
# (with "wasm validation error: too many locals" type errors) if optimizations
|
# (with "wasm validation error: too many locals" type errors) if optimizations
|
||||||
# are omitted. Enable optimizations also for debug builds.
|
# are omitted. Enable optimizations also for debug builds.
|
||||||
QMAKE_LFLAGS_DEBUG += -Os
|
QMAKE_LFLAGS_DEBUG += -Os
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Declare all async functions
|
# Declare async functions
|
||||||
QMAKE_LFLAGS += -s \'ASYNCIFY_IMPORTS=[\"qt_asyncify_suspend_js\", \"qt_asyncify_resume_js\", \"emscripten_sleep\"]\'
|
QMAKE_LFLAGS += -s \'ASYNCIFY_IMPORTS=qt_asyncify_suspend_js,qt_asyncify_resume_js\'
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EMCC_COMMON_LFLAGS += \
|
EMCC_COMMON_LFLAGS += \
|
||||||
-s WASM=1 \
|
-s WASM=1 \
|
||||||
|
@ -26,14 +26,16 @@ Q_LOGGING_CATEGORY(lcEventDispatcherTimers, "qt.eventdispatcher.timers");
|
|||||||
#define LOCK_GUARD(M)
|
#define LOCK_GUARD(M)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY
|
|
||||||
|
|
||||||
// Emscripten asyncify currently supports one level of suspend -
|
// Emscripten asyncify currently supports one level of suspend -
|
||||||
// recursion is not permitted. We track the suspend state here
|
// recursion is not permitted. We track the suspend state here
|
||||||
// on order to fail (more) gracefully, but we can of course only
|
// on order to fail (more) gracefully, but we can of course only
|
||||||
// track Qts own usage of asyncify.
|
// track Qts own usage of asyncify.
|
||||||
static bool g_is_asyncify_suspended = false;
|
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, (), {
|
EM_JS(void, qt_asyncify_suspend_js, (), {
|
||||||
let sleepFn = (wakeUp) => {
|
let sleepFn = (wakeUp) => {
|
||||||
Module.qtAsyncifyWakeUp = wakeUp;
|
Module.qtAsyncifyWakeUp = wakeUp;
|
||||||
@ -52,6 +54,15 @@ EM_JS(void, qt_asyncify_resume_js, (), {
|
|||||||
setTimeout(wakeUp);
|
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
|
// Suspends the main thread until qt_asyncify_resume() is called. Returns
|
||||||
// false immediately if Qt has already suspended the main thread (recursive
|
// false immediately if Qt has already suspended the main thread (recursive
|
||||||
// suspend is not supported by Emscripten). Returns true (after resuming),
|
// suspend is not supported by Emscripten). Returns true (after resuming),
|
||||||
@ -76,8 +87,6 @@ bool qt_asyncify_resume()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // QT_HAVE_EMSCRIPTEN_ASYNCIFY
|
|
||||||
|
|
||||||
Q_CONSTINIT QEventDispatcherWasm *QEventDispatcherWasm::g_mainThreadEventDispatcher = nullptr;
|
Q_CONSTINIT QEventDispatcherWasm *QEventDispatcherWasm::g_mainThreadEventDispatcher = nullptr;
|
||||||
#if QT_CONFIG(thread)
|
#if QT_CONFIG(thread)
|
||||||
Q_CONSTINIT QVector<QEventDispatcherWasm *> QEventDispatcherWasm::g_secondaryThreadEventDispatchers;
|
Q_CONSTINIT QVector<QEventDispatcherWasm *> QEventDispatcherWasm::g_secondaryThreadEventDispatchers;
|
||||||
@ -359,16 +368,15 @@ void QEventDispatcherWasm::handleApplicationExec()
|
|||||||
|
|
||||||
void QEventDispatcherWasm::handleDialogExec()
|
void QEventDispatcherWasm::handleDialogExec()
|
||||||
{
|
{
|
||||||
#ifndef QT_HAVE_EMSCRIPTEN_ASYNCIFY
|
if (!qt_have_asyncify()) {
|
||||||
qWarning() << "Warning: dialog exec() is not supported on Qt for WebAssembly in this"
|
qWarning() << "Warning: dialog exec() is not supported on Qt for WebAssembly in this"
|
||||||
<< "configuration. Please use show() instead, or enable experimental support"
|
<< "configuration. Please use show() instead, or enable experimental support"
|
||||||
<< "for asyncify.\n"
|
<< "for asyncify.\n"
|
||||||
<< "When using exec() (without asyncify) the dialog will show, the user can interact"
|
<< "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"
|
<< "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";
|
<< "is leaked, and the exec() call may interfere with input event processing";
|
||||||
emscripten_sleep(1); // This call never returns
|
emscripten_sleep(1); // This call never returns
|
||||||
#endif
|
}
|
||||||
// For the asyncify case we do nothing here and wait for events in wait()
|
// For the asyncify case we do nothing here and wait for events in wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,7 +401,7 @@ bool QEventDispatcherWasm::wait(int timeout)
|
|||||||
#endif
|
#endif
|
||||||
Q_ASSERT(emscripten_is_main_runtime_thread());
|
Q_ASSERT(emscripten_is_main_runtime_thread());
|
||||||
Q_ASSERT(isMainThreadEventDispatcher());
|
Q_ASSERT(isMainThreadEventDispatcher());
|
||||||
#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY
|
if (qt_have_asyncify()) {
|
||||||
if (timeout > 0)
|
if (timeout > 0)
|
||||||
qWarning() << "QEventDispatcherWasm asyncify wait with timeout is not supported; timeout will be ignored"; // FIXME
|
qWarning() << "QEventDispatcherWasm asyncify wait with timeout is not supported; timeout will be ignored"; // FIXME
|
||||||
|
|
||||||
@ -403,10 +411,10 @@ bool QEventDispatcherWasm::wait(int timeout)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
#else
|
} else {
|
||||||
qWarning("QEventLoop::WaitForMoreEvents is not supported on the main thread without asyncify");
|
qWarning("QEventLoop::WaitForMoreEvents is not supported on the main thread without asyncify");
|
||||||
Q_UNUSED(timeout);
|
Q_UNUSED(timeout);
|
||||||
#endif
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,12 +432,10 @@ bool QEventDispatcherWasm::wakeEventDispatcherThread()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
Q_ASSERT(isMainThreadEventDispatcher());
|
Q_ASSERT(isMainThreadEventDispatcher());
|
||||||
#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY
|
|
||||||
if (g_is_asyncify_suspended) {
|
if (g_is_asyncify_suspended) {
|
||||||
runOnMainThread([]{ qt_asyncify_resume(); });
|
runOnMainThread([]{ qt_asyncify_resume(); });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,3 +7,6 @@ qt_internal_add_manual_test(asyncify_exec
|
|||||||
LIBRARIES
|
LIBRARIES
|
||||||
Qt::Core
|
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)
|
||||||
|
@ -2,14 +2,12 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
#include <QtCore>
|
#include <QtCore>
|
||||||
|
|
||||||
// This test shows how to asyncify enables blocking
|
// This test shows how to use asyncify to enable blocking the main
|
||||||
// the main thread on QEventLoop::exec(), while event
|
// thread on QEventLoop::exec(), while event processing continues.
|
||||||
// provessing continues.
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
QCoreApplication app(argc, argv);
|
QCoreApplication app(argc, argv);
|
||||||
|
|
||||||
#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY
|
|
||||||
QTimer::singleShot(1000, []() {
|
QTimer::singleShot(1000, []() {
|
||||||
|
|
||||||
QEventLoop loop;
|
QEventLoop loop;
|
||||||
@ -22,10 +20,6 @@ int main(int argc, char **argv)
|
|||||||
loop.exec();
|
loop.exec();
|
||||||
qDebug() << "Returned from QEventLoop::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();
|
app.exec();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user