-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move the engine pause logic in a dedicated object
- Loading branch information
1 parent
a87fd88
commit 633c84d
Showing
9 changed files
with
196 additions
and
125 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
#include "controllers/controllerenginethreadcontrol.h" | ||
|
||
#include <QCoreApplication> | ||
|
||
#include "moc_controllerenginethreadcontrol.cpp" | ||
#include "util/assert.h" | ||
#include "util/logger.h" | ||
#include "util/mutex.h" | ||
#include "util/thread_affinity.h" | ||
|
||
namespace { | ||
const mixxx::Logger kLogger("ControllerEngineThreadControl"); | ||
constexpr int kMaxPauseDurationMilliseconds = 1000; | ||
} // namespace | ||
|
||
ControllerEngineThreadControl::ControllerEngineThreadControl(QObject* parent) | ||
: QObject(parent) { | ||
} | ||
bool ControllerEngineThreadControl::pause() { | ||
VERIFY_OR_DEBUG_ASSERT_THIS_QOBJECT_THREAD_ANTI_AFFINITY() { | ||
return false; | ||
} | ||
const auto lock = lockMutex(&m_pauseMutex); | ||
m_pauseCount++; | ||
|
||
if (m_canPause && !m_isPaused) { | ||
emit pauseRequested(); | ||
} | ||
|
||
while (m_canPause && !m_isPaused) { | ||
if (!m_isPausedCondition.wait(&m_pauseMutex, kMaxPauseDurationMilliseconds)) { | ||
kLogger.warning() << "Pause request timed out!"; | ||
m_pauseCount--; | ||
return false; | ||
} | ||
} | ||
return !m_canPause || m_isPaused; | ||
} | ||
void ControllerEngineThreadControl::resume() { | ||
VERIFY_OR_DEBUG_ASSERT_THIS_QOBJECT_THREAD_ANTI_AFFINITY() { | ||
return; | ||
} | ||
const auto lock = lockMutex(&m_pauseMutex); | ||
if (m_pauseCount > 0) { | ||
m_pauseCount--; | ||
} | ||
m_isPaused = m_pauseCount > 0; | ||
m_isPausedCondition.wakeOne(); | ||
} | ||
void ControllerEngineThreadControl::setCanPause(bool canPause) { | ||
DEBUG_ASSERT_THIS_QOBJECT_THREAD_AFFINITY(); | ||
auto lock = lockMutex(&m_pauseMutex); | ||
m_canPause = canPause; | ||
|
||
if (m_canPause) { | ||
connect(this, | ||
&ControllerEngineThreadControl::pauseRequested, | ||
this, | ||
&ControllerEngineThreadControl::doPause, | ||
Qt::UniqueConnection); | ||
} else { | ||
// New signals may have been queued emitted requesting for pause, so we | ||
// manually process the event loop now to clear and handle those, before | ||
// disabling pausing. Without this, thread requesting pause will stay | ||
// stuck waiting on the condvar | ||
lock.unlock(); | ||
QCoreApplication::processEvents(); | ||
lock.relock(); | ||
|
||
disconnect(this, | ||
&ControllerEngineThreadControl::pauseRequested, | ||
this, | ||
&ControllerEngineThreadControl::doPause); | ||
|
||
m_isPaused = false; | ||
m_pauseCount = 0; | ||
m_isPausedCondition.wakeOne(); | ||
} | ||
} | ||
void ControllerEngineThreadControl::doPause() { | ||
VERIFY_OR_DEBUG_ASSERT_THIS_QOBJECT_THREAD_AFFINITY() { | ||
return; | ||
} | ||
const auto lock = lockMutex(&m_pauseMutex); | ||
m_isPaused = m_pauseCount > 0; | ||
m_isPausedCondition.wakeOne(); | ||
|
||
while (m_canPause && m_isPaused) { | ||
VERIFY_OR_DEBUG_ASSERT(m_isPausedCondition.wait( | ||
&m_pauseMutex, kMaxPauseDurationMilliseconds)) { | ||
kLogger.warning() << "Engine pause timed out!"; | ||
m_isPaused = false; | ||
m_pauseCount = 0; | ||
}; | ||
} | ||
m_isPausedCondition.wakeAll(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#pragma once | ||
|
||
#include <QMutex> | ||
#include <QObject> | ||
#include <QWaitCondition> | ||
|
||
/// @brief A ControllerEngineThreadControl can be use to orchestrate thread | ||
/// pause on a ControllerScriptEngineBase. It used Pause is required by | ||
/// rendering thread (https://doc.qt.io/qt-6/qquickrendercontrol.html#sync). | ||
/// This offscreen render thread to pause the main "GUI thread" for onboard | ||
/// screens | ||
/// The documentation isn't completely clear about this, but after | ||
/// testing, it appears that the "GUI main thread" is the thread where the QML | ||
/// engine leaves in (also the main thread if we were using a | ||
/// QMLApplication, which isn't the case here) | ||
class ControllerEngineThreadControl : public QObject { | ||
Q_OBJECT | ||
public: | ||
explicit ControllerEngineThreadControl(QObject* parent = nullptr); | ||
|
||
public slots: | ||
// The following slots may be used by rendering engine to pause the thread. | ||
// They must be called from different thread than | ||
// ControllerEngineThreadControl's | ||
bool pause(); | ||
void resume(); | ||
|
||
// Change whether or not it is possible to pause the thread. Should be | ||
// called from eh same thread than ControllerEngineThreadControl | ||
void setCanPause(bool canPause); | ||
private slots: | ||
// Used to effectively pause the thread. Must be called from the same thread | ||
// than ControllerEngineThreadControl | ||
void doPause(); | ||
|
||
signals: | ||
void pauseRequested(); | ||
|
||
private: | ||
QWaitCondition m_isPausedCondition; | ||
QMutex m_pauseMutex; | ||
int m_pauseCount{0}; | ||
bool m_isPaused{false}; | ||
bool m_canPause{false}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.