diff options
author | Mauro Persano <mauro.persano@kdab.com> | 2018-07-02 19:54:22 -0300 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2018-07-04 17:06:16 +0000 |
commit | a1873c9f0d3cdc97744b3237b1fea1341b59c800 (patch) | |
tree | d2a58f4b20ccdfcc84bcba376dd50be310cc57ea /src | |
parent | e75e49434fa8930037ae72b50c998e899739b91f (diff) |
Avoid busy loop in QAspectManager while simulation loop is not started
After QAspectThread starts, it gets in a busy loop until
QAspectManager::enterSimulationLoop is called.
Make the aspect thread's main loop block on QEventLoop::processEvents
until it's told to start the simulation loop.
Task-number: QTBUG-67823
Change-Id: I3daac20b65227787c42907d53c11609e1a87ea85
Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/core/aspects/qaspectmanager.cpp | 71 |
1 files changed, 36 insertions, 35 deletions
diff --git a/src/core/aspects/qaspectmanager.cpp b/src/core/aspects/qaspectmanager.cpp index 0b00e6ef3..e9642116a 100644 --- a/src/core/aspects/qaspectmanager.cpp +++ b/src/core/aspects/qaspectmanager.cpp @@ -41,6 +41,7 @@ #include <Qt3DCore/qabstractaspect.h> #include <Qt3DCore/qentity.h> +#include <QtCore/QAbstractEventDispatcher> #include <QtCore/QEventLoop> #include <QtCore/QThread> #include <QtCore/QWaitCondition> @@ -103,6 +104,9 @@ void QAspectManager::enterSimulationLoop() qCDebug(Aspects) << Q_FUNC_INFO; m_runSimulationLoop.fetchAndStoreOrdered(1); + // Wake up QAspectThread's event loop + thread()->eventDispatcher()->wakeUp(); + // We wait for the setRootEntity on the aspectManager to have completed // This ensures we cannot shutdown before the aspects have had a chance // to be initialized @@ -255,33 +259,29 @@ void QAspectManager::exec() // Enter the engine loop qCDebug(Aspects) << Q_FUNC_INFO << "***** Entering main loop *****"; while (m_runMainLoop.load()) { - // Process any pending events, waiting for more to arrive if queue is empty - eventLoop.processEvents(QEventLoop::AllEvents, 16); + // Process events until we're told to start the simulation loop + while (m_runMainLoop.load() && !m_runSimulationLoop.load()) + eventLoop.processEvents(QEventLoop::AllEvents | QEventLoop::WaitForMoreEvents); + + if (!m_runSimulationLoop.load()) + break; // Retrieve the frame advance service. Defaults to timer based if there is no renderer. QAbstractFrameAdvanceService *frameAdvanceService = m_serviceLocator->service<QAbstractFrameAdvanceService>(QServiceLocator::FrameAdvanceService); - // Start the frameAdvanceService if we're about to enter the simulation loop - bool needsShutdown = false; - if (m_runSimulationLoop.load()) { - needsShutdown = true; - frameAdvanceService->start(); - - // We are about to enter the simulation loop. Give aspects a chance to do any last - // pieces of initialization - qCDebug(Aspects) << "Calling onEngineStartup() for each aspect"; - for (QAbstractAspect *aspect : qAsConst(m_aspects)) { - qCDebug(Aspects) << "\t" << aspect->objectName(); - aspect->onEngineStartup(); - } - qCDebug(Aspects) << "Done calling onEngineStartup() for each aspect"; - m_waitForStartOfSimulationLoop.release(1); - } else { - continue; - // Ensure we won't enter the simulation loop (in case the atomic was changed between - // the last time we read it) without having performed the initialization first + // Start the frameAdvanceService + frameAdvanceService->start(); + + // We are about to enter the simulation loop. Give aspects a chance to do any last + // pieces of initialization + qCDebug(Aspects) << "Calling onEngineStartup() for each aspect"; + for (QAbstractAspect *aspect : qAsConst(m_aspects)) { + qCDebug(Aspects) << "\t" << aspect->objectName(); + aspect->onEngineStartup(); } + qCDebug(Aspects) << "Done calling onEngineStartup() for each aspect"; + m_waitForStartOfSimulationLoop.release(1); // Only enter main simulation loop once the renderer and other aspects are initialized while (m_runSimulationLoop.load()) { @@ -325,22 +325,20 @@ void QAspectManager::exec() eventLoop.processEvents(); } // End of simulation loop - if (needsShutdown) { - // Process any pending changes from the frontend before we shut the aspects down - m_changeArbiter->syncChanges(); + // Process any pending changes from the frontend before we shut the aspects down + m_changeArbiter->syncChanges(); - // Give aspects a chance to perform any shutdown actions. This may include unqueuing - // any blocking work on the main thread that could potentially deadlock during shutdown. - qCDebug(Aspects) << "Calling onEngineShutdown() for each aspect"; - for (QAbstractAspect *aspect : qAsConst(m_aspects)) { - qCDebug(Aspects) << "\t" << aspect->objectName(); - aspect->onEngineShutdown(); - } - qCDebug(Aspects) << "Done calling onEngineShutdown() for each aspect"; - - // Wake up the main thread which is waiting for us inside of exitSimulationLoop() - m_waitForEndOfSimulationLoop.release(1); + // Give aspects a chance to perform any shutdown actions. This may include unqueuing + // any blocking work on the main thread that could potentially deadlock during shutdown. + qCDebug(Aspects) << "Calling onEngineShutdown() for each aspect"; + for (QAbstractAspect *aspect : qAsConst(m_aspects)) { + qCDebug(Aspects) << "\t" << aspect->objectName(); + aspect->onEngineShutdown(); } + qCDebug(Aspects) << "Done calling onEngineShutdown() for each aspect"; + + // Wake up the main thread which is waiting for us inside of exitSimulationLoop() + m_waitForEndOfSimulationLoop.release(1); } // End of main loop qCDebug(Aspects) << Q_FUNC_INFO << "***** Exited main loop *****"; @@ -355,6 +353,9 @@ void QAspectManager::quit() Q_ASSERT_X(m_runSimulationLoop.load() == 0, "QAspectManagr::quit()", "Inner loop is still running"); m_runMainLoop.fetchAndStoreOrdered(0); + // Wake up QAspectThread's event loop if needed + thread()->eventDispatcher()->wakeUp(); + // We need to wait for the QAspectManager exec loop to terminate m_waitForEndOfExecLoop.acquire(1); m_waitForQuit.release(1); |