diff options
author | Morten Johan Sørvig <morten.sorvig@qt.io> | 2020-10-22 11:58:47 +0200 |
---|---|---|
committer | Morten Johan Sørvig <morten.sorvig@qt.io> | 2020-11-04 10:17:09 +0000 |
commit | 4035fdd820d75a1145f4b5320c14664a5cecc2cb (patch) | |
tree | 5595efd705ad79fa405853a5fb1e89b34202bc1a /src/plugins/platforms/wasm/qwasmeventdispatcher.cpp | |
parent | f9e45287d820b8af2d40050288034c7ba8262d26 (diff) |
wasm: don’t deadlock on event processing
emscripten_async_run_in_main_runtime_thread_ schedules
an async call on the on the main thread. However, the
calls are ordered, also in respect to _synchronous_ calls
to the main thread (for example those made during file
write/flush).
Making a synchronous call from a secondary thread may
then cause Emscripten to service previously scheduled
async calls during the synchronous call. This can cause
a deadlock if:
- a secondary thread makes a sync call while holding a lock, and
- a previously scheduled async call attempt to acquire the same
lock on the main thread.
(See https://github.com/emscripten-core/emscripten/issues/10155
for sample code)
Avoid this case by adding a second zero-timer async call;
this way Qt should process events when the main thread
becomes idle.
Change-Id: I221fe4e25bbb1a56627e63c3d1809e40ccefb030
Pick-to: 5.15
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
Diffstat (limited to 'src/plugins/platforms/wasm/qwasmeventdispatcher.cpp')
-rw-r--r-- | src/plugins/platforms/wasm/qwasmeventdispatcher.cpp | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp index 1902f8a4a7..29dbf96883 100644 --- a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp +++ b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp @@ -195,9 +195,15 @@ void QWasmEventDispatcher::doMaintainTimers() void QWasmEventDispatcher::wakeUp() { #ifdef EMSCRIPTEN_HAS_ASYNC_RUN_IN_MAIN_RUNTIME_THREAD - if (!emscripten_is_main_runtime_thread()) - if (m_hasMainLoop) - emscripten_async_run_in_main_runtime_thread_(EM_FUNC_SIG_VI, (void*)(&QWasmEventDispatcher::mainThreadWakeUp), this); + if (!emscripten_is_main_runtime_thread() && m_hasMainLoop) { + + // Make two-step async call to mainThreadWakeUp in order to make sure the + // call is made at a point where the main thread is idle. + void (*intermediate)(void *) = [](void *eventdispatcher){ + emscripten_async_call(QWasmEventDispatcher::mainThreadWakeUp, eventdispatcher, 0); + }; + emscripten_async_run_in_main_runtime_thread_(EM_FUNC_SIG_VI, (void *)intermediate, this); + } #endif QEventDispatcherUNIX::wakeUp(); } |