Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-89496

[wasm] Event handling reentrant occurred with multi-threaded qt-wasm 5.15

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Open
    • Priority: P2: Important
    • Resolution: Unresolved
    • Affects Version/s: 5.15.2
    • Fix Version/s: None
    • Component/s: Core: Event loop
    • Labels:
      None
    • Environment:
      qt-5.15
      emscripten 2.0.8
      ubuntu 18.04
    • Platform/s:
      WebAssembly

      Description

          Recently We found some deadlocks in our web-assembly app, after some investigation I found that the deadlock is caused by reentrant of Qt event handling with multi-threaded qt-wasm 5.15. I build qt-5.15 from git with emscripten 2.0.8 with thread enabled.

          Below is a callstack when deadlock happened:

      _emscripten_futex_wait (VM12:8491)
      __timedwait_cp (type_traits:2261)
      __timedwait (type_traits:2261)
      __pthread_mutex_timedlock (type_traits:2261)
      __pthread_mutex_lock (type_traits:2261)
      std::_2::_libcpp_mutex_lock(pthread_mutex_t*) (type_traits:2261)
      std::__2::mutex::lock() (type_traits:2261)
      std::_2::lock_guard<std::2::mutex>::lock_guard(std::2::mutex&) (_mutex_base:91)
      CNvPlatformEventHandler::SendPostedEventByEventHandlerId(long long) (NvPlatformEventHandler.cpp:246)
      CNvQtEventHandler::customEvent(QEvent*) (NvPlatformEventHandler.cpp:115)
      QObject::event(QEvent*) (type_traits:2261)
      QCoreApplicationPrivate::notify_helper(QObject*, QEvent*) (type_traits:2261)
      QCoreApplication::notify(QObject*, QEvent*) (type_traits:2261)
      QGuiApplication::notify(QObject*, QEvent*) (type_traits:2261)
      QCoreApplication::notifyInternal2(QObject*, QEvent*) (type_traits:2261)
      QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) (type_traits:2261)
      QEventDispatcherUNIX::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) (type_traits:2261)
      QUnixEventDispatcherQPA::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) (type_traits:2261)
      QWasmEventDispatcher::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) (type_traits:2261)
      QWasmEventDispatcher::mainThreadWakeUp(void*) (type_traits:2261)
      _do_call (type_traits:2261)
      emscripten_current_thread_process_queued_calls (type_traits:2261)
      emscripten_main_thread_process_queued_calls (type_traits:2261)
      __timedwait_cp (type_traits:2261)
      __timedwait (type_traits:2261)
      __pthread_mutex_timedlock (type_traits:2261)
      __pthread_mutex_lock (type_traits:2261)
      dlfree (type_traits:2261)
      SNvArrayData::deallocate(SNvArrayData*, unsigned long, unsigned long) (NvArrayData.cpp:131)
      SNvTypedArrayData<unsigned short>::deallocate(SNvArrayData*) (NvArrayData.h:134)
      CNvString::~CNvString() (NvString.h:786)
      CNvDebugLog::Stream::~Stream() (NvDebug.h:101)
      CNvDebugLog::DropStream() (NvDebug.cpp:372)
      CNvDebugLog::~CNvDebugLog() (NvDebug.cpp:128)
      CNvWebReaderManager::TryAbortWebRequest() (NvWebReaderManager.cpp:658)
      CNvWebReaderManager::SendWebRequest(CNvBaseWebReader*, int, int, bool) (NvWebReaderManager.cpp:609)
      CNvWebReaderManager::ProcessEvent(CNvEvent*) (NvWebReaderManager.cpp:422)
      CNvPlatformEventHandler::SendPostedEvent(int) (NvPlatformEventHandler.cpp:217)
      CNvPlatformEventHandler::SendPostedEventByEventHandlerId(long long) (NvPlatformEventHandler.cpp:249)
      CNvQtEventHandler::customEvent(QEvent*) (NvPlatformEventHandler.cpp:115)
      QObject::event(QEvent*) (type_traits:2261)
      QCoreApplicationPrivate::notify_helper(QObject*, QEvent*) (type_traits:2261)
      QCoreApplication::notify(QObject*, QEvent*) (type_traits:2261)
      QGuiApplication::notify(QObject*, QEvent*) (type_traits:2261)
      QCoreApplication::notifyInternal2(QObject*, QEvent*) (type_traits:2261)
      QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) (type_traits:2261)
      QEventDispatcherUNIX::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) (type_traits:2261)
      QUnixEventDispatcherQPA::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) (type_traits:2261)
      QWasmEventDispatcher::doMaintainTimers()::$1::_invoke(void*) (type_traits:2261)

          The scenario is that we post QEvent from a child thread to the main thread to trigger main thread working on a work queue, in the main thread's qt event handler we will do work in the work queue one by one with a lock held. To my surprise QWasmEventDispatcher::processEvents() get called while we do work of the queue as you can see in the callstack:

      QWasmEventDispatcher::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) (type_traits:2261)
      QWasmEventDispatcher::mainThreadWakeUp(void*) (type_traits:2261)
      _do_call (type_traits:2261)
      emscripten_current_thread_process_queued_calls (type_traits:2261)
      emscripten_main_thread_process_queued_calls (type_traits:2261)
      __timedwait_cp (type_traits:2261)
      __timedwait (type_traits:2261)
      __pthread_mutex_timedlock (type_traits:2261)
      __pthread_mutex_lock (type_traits:2261)
      dlfree (type_traits:2261)

          That is to say: when I call ::free() C runtime function implemented by emscritpen, emscritpen will call emscripten_main_thread_process_queued_calls() in the mean time. (I think this is deliberately since emscripten always proxy some work to main thread which is called from child thread) But that trigger a QWasmEventDispatcher::mainThreadWakeUp() function call and then QWasmEventDispatcher::processEvents() get called. A reentrant happened!
          I know I can solve my deadlock with a very simple solution, But I think the more serious problem is Qt event handling reentrant which will cause unexpected problems.

        Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

            Assignee:
            lpotter Lorn Potter
            Reporter:
            jianliang79 liang jian
            PM Owner:
            Veli-Pekka Heinonen Veli-Pekka Heinonen
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Dates

              Created:
              Updated:

                Gerrit Reviews

                There are no open Gerrit changes