Issue #11 Improve CEventLoop API

This commit is contained in:
Mat Sutcliffe
2021-09-28 18:34:25 +01:00
parent 3bd4b47d65
commit 002cd1d5b9
4 changed files with 38 additions and 41 deletions

View File

@@ -426,11 +426,12 @@ namespace BlackCore
CStatusMessageList CApplication::waitForSetup(int timeoutMs) CStatusMessageList CApplication::waitForSetup(int timeoutMs)
{ {
if (!m_setupReader) { return CStatusMessage(this).error(u"No setup reader"); } if (!m_setupReader) { return CStatusMessage(this).error(u"No setup reader"); }
CEventLoop::processEventsUntil(this, &CApplication::setupHandlingCompleted, timeoutMs, [this] CEventLoop eventLoop;
eventLoop.stopWhen(this, &CApplication::setupHandlingCompleted);
if (!m_setupReader->isSetupAvailable())
{ {
// init, if this is true event queue is not started eventLoop.exec(timeoutMs);
return m_setupReader->isSetupAvailable(); }
});
// setup handling completed with success or failure, or we run into time out // setup handling completed with success or failure, or we run into time out
CStatusMessageList msgs; CStatusMessageList msgs;

View File

@@ -152,7 +152,8 @@ namespace BlackCore::Db
{ {
// just give the system some time to relax, consolidation is time consuming // just give the system some time to relax, consolidation is time consuming
if (!this->doWorkCheck()) { return; } if (!this->doWorkCheck()) { return; }
CEventLoop::processEventsFor(1000); CEventLoop eventLoop;
eventLoop.exec(1000);
} }
} }
} }

View File

@@ -25,47 +25,41 @@ namespace BlackMisc
class CEventLoop class CEventLoop
{ {
public: public:
//! Deleted constructor //! Event loop will stop if the given signal is received.
CEventLoop() = delete;
//! Wait for the given time, while processing events.
static void processEventsFor(int timeoutMs)
{
QEventLoop eventLoop;
QTimer::singleShot(timeoutMs, &eventLoop, &QEventLoop::quit);
eventLoop.exec();
}
//! Block, but keep processing events, until sender emits the signal or the timeout expires.
//! Return true if the signal was emitted, false if the timeout expired.
template <typename T, typename F> template <typename T, typename F>
static bool processEventsUntil(const T *sender, F signal, int timeoutMs) void stopWhen(const T *sender, F signal)
{ {
return processEventsUntil(sender, signal, timeoutMs, [] {}); QObject::connect(sender, signal, &m_eventLoop, [this] { m_eventLoop.exit(GotSignal); });
} }
//! Overloaded version that executes an initial function after connecting the signal. //! Event loop will stop if the given signal is received and condition returns true.
//! If the function's return type is convertible to bool, and it evaluates to true,
//! then the waiting will immediately time out and return true.
template <typename T, typename F1, typename F2> template <typename T, typename F1, typename F2>
static bool processEventsUntil(const T *sender, F1 signal, int timeoutMs, F2 init) void stopWhen(const T *sender, F1 signal, F2 &&condition)
{ {
QEventLoop eventLoop; QObject::connect(sender, signal, &m_eventLoop, [this, condition = std::forward<F2>(condition)](auto &&... args)
bool result = false;
QObject::connect(sender, signal, &eventLoop, [ & ]
{ {
result = true; if (condition(std::forward<decltype(args)>(args)...)) { m_eventLoop.exit(GotSignal); }
eventLoop.quit();
}); });
if constexpr (std::is_void_v<decltype(init())>) { init(); }
else if (init()) { return true; }
if (timeoutMs > 0)
{
QTimer::singleShot(timeoutMs, &eventLoop, &QEventLoop::quit);
}
eventLoop.exec();
return result;
} }
//! Begin processing events until the timeout or stop condition occurs.
//! \return True if the signal was received, false if it timed out.
bool exec(int timeoutMs)
{
if (timeoutMs >= 0)
{
QTimer::singleShot(timeoutMs, &m_eventLoop, [this] { m_eventLoop.exit(TimedOut); });
}
return m_eventLoop.exec() == GotSignal;
}
private:
enum Result
{
GotSignal = 0,
TimedOut,
};
QEventLoop m_eventLoop;
}; };
} // ns } // ns

View File

@@ -81,10 +81,11 @@ namespace BlackMisc::Network
QObject::connect(&socket, &QTcpSocket::connected, &mapper, qOverload<>(&QSignalMapper::map)); QObject::connect(&socket, &QTcpSocket::connected, &mapper, qOverload<>(&QSignalMapper::map));
QObject::connect(&socket, qOverload<QAbstractSocket::SocketError>(&QTcpSocket::error), &mapper, qOverload<>(&QSignalMapper::map)); QObject::connect(&socket, qOverload<QAbstractSocket::SocketError>(&QTcpSocket::error), &mapper, qOverload<>(&QSignalMapper::map));
mapper.setMapping(&socket, 0); mapper.setMapping(&socket, 0);
const bool timedOut = !CEventLoop::processEventsUntil(&mapper, qOverload<int>(&QSignalMapper::mapped), timeoutMs, [&]
{ CEventLoop eventLoop;
socket.connectToHost(hostAddress, static_cast<quint16>(port)); eventLoop.stopWhen(&mapper, qOverload<int>(&QSignalMapper::mapped));
}); socket.connectToHost(hostAddress, static_cast<quint16>(port));
const bool timedOut = !eventLoop.exec(timeoutMs);
if (socket.state() != QTcpSocket::ConnectedState) if (socket.state() != QTcpSocket::ConnectedState)
{ {