From 4035fdd820d75a1145f4b5320c14664a5cecc2cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Thu, 22 Oct 2020 11:58:47 +0200 Subject: =?UTF-8?q?wasm:=20don=E2=80=99t=20deadlock=20on=20event=20process?= =?UTF-8?q?ing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/plugins/platforms/wasm/qwasmeventdispatcher.cpp | 12 +++++++++--- 1 file 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(); } -- cgit v1.2.3