Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sendEvent assert in Qt 5.15.2 about crossing different threads #457

Open
darksylinc opened this issue Aug 7, 2022 · 2 comments
Open

sendEvent assert in Qt 5.15.2 about crossing different threads #457

darksylinc opened this issue Aug 7, 2022 · 2 comments
Labels
bug Something isn't working help wanted Extra attention is needed

Comments

@darksylinc
Copy link
Contributor

darksylinc commented Aug 7, 2022

Environment

  • OS Version: Ubuntu 20.04
  • Source or binary build?
    main

Description

  • Expected behavior: Everything runs normally
  • Actual behavior: When starting Gazebo GUI compiled against Qt 5.15.2 it will complain with:
[GUI] [Err] [Application.cc:885] [QT] ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 0x0x55555622e390. Receiver '' (of type 'gz::gui::MainWindow') was created in thread 0x0x555555a1ebe0", file /mnt/ZLinuxDatos/qt-everywhere-src-5.15.2/qtbase/src/corelib/kernel/qcoreapplication.cpp, line 552

Steps to reproduce

  1. Install Qt 5.15.2
  2. Compile against it, using colcon build --cmake-args -DBUILD_TESTING=OFF -DBUILD_DOCS=OFF -DCMAKE_PREFIX_PATH=/opt/Qt/5.15.2/gcc_64 -DQT_QMAKE_EXECUTABLE=/opt/Qt/5.15.2/gcc_64/bin/qmake --merge-install
  3. Go to the install folder
  4. Run:
export LD_LIBRARY_PATH=/opt/Qt/5.15.2/gcc_64/lib
. setup.bash
gz sim shapes.sdf
  1. Note: I'm running a custom-compiled (Debug version) of Qt 5.15.2; so it's possible additional debug checks are being ran that aren't made in the Release version. UPDATE: Confirmed that this assert only triggers in Debug builds from Qt. Release versions don't exhibit this crash.

It is possible that this bug repros out of the box on Ubuntu 22.04 since it comes with Qt 5.15 by default.

Output

The error happens in GzRenderer::Render:

  if (gz::gui::App())
  {
    gz::gui::App()->sendEvent(
        gz::gui::App()->findChild<gz::gui::MainWindow *>(),
        new gui::events::PreRender());
  }

Qt does not like that sendEvent() call.

Full callstack:

                                                                                                     
                                                                                                     
1  __GI_raise                                          raise.c                   50   0x7ffff7a5100b 
2  __GI_abort                                          abort.c                   79   0x7ffff7a30859 
3  qt_message_fatal                                    qlogging.cpp              1914 0x7ffff14aaf32 
4  QMessageLogger::fatal                               qlogging.cpp              893  0x7ffff14abc6f 
5  qt_assert_x                                         qlogging.h                90   0x7ffff14a4d22 
6  QCoreApplicationPrivate::checkReceiverThread        qarraydata.h              208  0x7ffff16cdc1d 
7  QApplication::notify                                qapplication.cpp          2870 0x7ffff0977e10 
8  QCoreApplication::notifyInternal2                   qcoreapplication.cpp      1063 0x7ffff16ce38d 
9  QCoreApplication::sendEvent                         qcoreapplication.cpp      1458 0x7ffff16ce5c6 
10 gz::gui::plugins::GzRenderer::Render                MinimalScene.cc           338  0x7fffca3afac8 
11 gz::gui::plugins::RenderThreadRhiOpenGL::RenderNext MinimalSceneRhiOpenGL.cc  167  0x7fffca3cff89 
12 gz::gui::plugins::RenderThread::RenderNext          MinimalScene.cc           732  0x7fffca3b2d17 
13 gz::gui::plugins::RenderThread::qt_static_metacall  moc_MinimalScene.cpp      282  0x7fffca3d6cc3 
14 QMetaCallEvent::placeMetaCall                       qobject.cpp               617  0x7ffff170150e 
15 QObject::event                                      qobject.cpp               1314 0x7ffff17092a5 
16 QThread::event                                      qthread.cpp               1012 0x7ffff14b535e 
17 QApplicationPrivate::notify_helper                  qapplication.cpp          3632 0x7ffff096f1b8 
18 QApplication::notify                                qapplication.cpp          2972 0x7ffff0978192 
19 QCoreApplication::notifyInternal2                   qcoreapplication.cpp      1063 0x7ffff16ce38d 
20 QCoreApplication::sendEvent                         qcoreapplication.cpp      1458 0x7ffff16ce5c6 
21 QCoreApplicationPrivate::sendPostedEvents           qcoreapplication.cpp      1817 0x7ffff16d22d2 
22 QCoreApplication::sendPostedEvents                  qcoreapplication.cpp      1676 0x7ffff16d2996 
23 postEventSourceDispatch                             qeventdispatcher_glib.cpp 277  0x7ffff173d63b 
24 g_main_context_dispatch                                                            0x7ffff072917d 
25 ??                                                                                 0x7ffff0729400 
26 g_main_context_iteration                                                           0x7ffff07294a3 
27 QEventDispatcherGlib::processEvents                 qeventdispatcher_glib.cpp 423  0x7ffff173cf28 
28 QEventLoop::processEvents                           atomic_base.h             734  0x7ffff16cbdc5 
29 QEventLoop::exec                                    qflags.h                  125  0x7ffff16cc22e 
30 QThread::exec                                       qflags.h                  121  0x7ffff14b5294 
31 QThread::run                                        qthread.cpp               616  0x7ffff14b5345 
32 QThreadPrivate::start                               qthread_unix.cpp          329  0x7ffff14b6b44 
33 start_thread                                        pthread_create.c          477  0x7ffff7f71609 
34 clone                                               clone.S                   95   0x7ffff7b2d133 

I'll keep researching

@darksylinc
Copy link
Contributor Author

darksylinc commented Aug 7, 2022

Oh what a hell this is.

  1. Qt is right that the MainWindow does not belong to that thread.
  2. However we guarantee both threads (MainWindow's and Ogre) are not run simultaneously as we force serialization (since Fix race condition when rendering the UI gz-sim#774)
  3. Qt's intended way would be to call postEvent and wait for the results
  4. However the documentation of PreRender explicitly states: /// It's safe to make rendering calls in this event's callback.
    • Due to how OpenGL works (context sticks per thread) any rendering call must happen in the rendering thread
    • Any code (Qt, OS, or Gazebo's) that relies on TLS (Thread Local Storage) could break if they are in the wrong thread

Hence we've run into a contradiction: Qt debug checks want the event to happen in the Main thread; Gazebo wants the event to happen in the rendering thread.

The simplest (and best) solution would be to move the whole rendering to the Main thread, which is something I've been wanting to do since gazebosim/gz-sim#774

From the looks of it, this bug will not be fixable for Garden. The assert itself should be harmless as far as I can see; but if left unfixed it may become a problem in Ubuntu 22.04

@darksylinc
Copy link
Contributor Author

OK I just confirmed this only repros with DEBUG versions of Qt.

The Release version will not trigger the assert.

I can also verify this by looking at Qt's source code in QApplication::notify:

#ifndef QT_NO_DEBUG
    QCoreApplicationPrivate::checkReceiverThread(receiver);
#endif

That check is left out in non-debug builds.

This makes me rest a little easier since there won't be a problem with Ubuntu 22.04

@chapulina chapulina added the help wanted Extra attention is needed label Aug 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants