Process: Simplify timeout related internals

Get rid of two internal fields: m_hangTimerCount and m_waitingForUser.
Rename m_maxHangTimerCount into more meaningful m_timeoutInSeconds.
Fire single shot timers instead of a timer with interval.

Change-Id: I10890101273719f55a591eaecf818067aa5c503c
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
Jarek Kobus
2024-01-20 19:21:29 +01:00
parent 9aa37ee9d9
commit 767e11aa5d

View File

@@ -815,7 +815,6 @@ public:
std::unique_ptr<ProcessInterface> m_process; std::unique_ptr<ProcessInterface> m_process;
ProcessSetupData m_setup; ProcessSetupData m_setup;
void slotTimeout();
void handleStarted(qint64 processId, qint64 applicationMainThreadId); void handleStarted(qint64 processId, qint64 applicationMainThreadId);
void handleReadyRead(const QByteArray &outputData, const QByteArray &errorData); void handleReadyRead(const QByteArray &outputData, const QByteArray &errorData);
void handleDone(const ProcessResultData &data); void handleDone(const ProcessResultData &data);
@@ -842,10 +841,8 @@ public:
ChannelBuffer m_stdOut; ChannelBuffer m_stdOut;
ChannelBuffer m_stdErr; ChannelBuffer m_stdErr;
int m_hangTimerCount = 0; int m_timeoutInSeconds = 10;
int m_maxHangTimerCount = 10; // 10 seconds
bool m_timeOutMessageBoxEnabled = false; bool m_timeOutMessageBoxEnabled = false;
bool m_waitingForUser = false;
Guard m_guard; Guard m_guard;
}; };
@@ -1091,7 +1088,6 @@ void ProcessPrivate::sendControlSignal(ControlSignal controlSignal)
void ProcessPrivate::clearForRun() void ProcessPrivate::clearForRun()
{ {
m_hangTimerCount = 0;
m_stdOut.clearForRun(); m_stdOut.clearForRun();
m_stdOut.codec = m_codec; m_stdOut.codec = m_codec;
m_stdErr.clearForRun(); m_stdErr.clearForRun();
@@ -1820,14 +1816,14 @@ void ChannelBuffer::handleRest()
void Process::setTimeoutS(int timeoutS) void Process::setTimeoutS(int timeoutS)
{ {
if (timeoutS > 0) if (timeoutS > 0)
d->m_maxHangTimerCount = qMax(2, timeoutS); d->m_timeoutInSeconds = qMax(2, timeoutS);
else else
d->m_maxHangTimerCount = INT_MAX / 1000; d->m_timeoutInSeconds = INT_MAX / 1000;
} }
int Process::timeoutS() const int Process::timeoutS() const
{ {
return d->m_maxHangTimerCount; return d->m_timeoutInSeconds;
} }
void Process::setCodec(QTextCodec *c) void Process::setCodec(QTextCodec *c)
@@ -1864,10 +1860,6 @@ void Process::runBlocking(EventLoopMode eventLoopMode)
}; };
if (eventLoopMode == EventLoopMode::On) { if (eventLoopMode == EventLoopMode::On) {
QTimer timer(this);
connect(&timer, &QTimer::timeout, d, &ProcessPrivate::slotTimeout);
timer.setInterval(1000);
timer.start();
#ifdef QT_GUI_LIB #ifdef QT_GUI_LIB
if (isGuiEnabled()) if (isGuiEnabled())
QGuiApplication::setOverrideCursor(Qt::WaitCursor); QGuiApplication::setOverrideCursor(Qt::WaitCursor);
@@ -1875,23 +1867,38 @@ void Process::runBlocking(EventLoopMode eventLoopMode)
QEventLoop eventLoop(this); QEventLoop eventLoop(this);
QTC_ASSERT(!d->m_eventLoop, return); QTC_ASSERT(!d->m_eventLoop, return);
d->m_eventLoop = &eventLoop; d->m_eventLoop = &eventLoop;
// Queue the call to start() so that it's executed after the nested event loop is started, // Queue the call to start() so that it's executed after the nested event loop is started,
// otherwise it fails on Windows with QProcessImpl. See QTCREATORBUG-30066. // otherwise it fails on Windows with QProcessImpl. See QTCREATORBUG-30066.
QMetaObject::invokeMethod(this, starter, Qt::QueuedConnection); QMetaObject::invokeMethod(this, starter, Qt::QueuedConnection);
std::function<void(void)> timeoutHandler = {};
if (d->m_timeoutInSeconds > 0) {
timeoutHandler = [this, &eventLoop, &timeoutHandler] {
if (!d->m_timeOutMessageBoxEnabled || askToKill(d->m_setup.m_commandLine)) {
stop();
waitForFinished();
d->m_result = ProcessResult::Hang;
return;
}
QTimer::singleShot(d->m_timeoutInSeconds * 1000, &eventLoop, timeoutHandler);
};
QTimer::singleShot(d->m_timeoutInSeconds * 1000, &eventLoop, timeoutHandler);
}
eventLoop.exec(QEventLoop::ExcludeUserInputEvents); eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
d->m_eventLoop = nullptr; d->m_eventLoop = nullptr;
timer.stop();
#ifdef QT_GUI_LIB #ifdef QT_GUI_LIB
if (isGuiEnabled()) if (isGuiEnabled())
QGuiApplication::restoreOverrideCursor(); QGuiApplication::restoreOverrideCursor();
#endif #endif
} else { } else {
starter(); starter();
if (!waitForStarted(d->m_maxHangTimerCount * 1000)) { if (!waitForStarted(d->m_timeoutInSeconds * 1000)) {
d->m_result = ProcessResult::StartFailed; d->m_result = ProcessResult::StartFailed;
return; return;
} }
if (!waitForFinished(d->m_maxHangTimerCount * 1000)) { if (!waitForFinished(d->m_timeoutInSeconds * 1000)) {
d->m_result = ProcessResult::Hang; d->m_result = ProcessResult::Hang;
terminate(); terminate();
if (!waitForFinished(1000)) { if (!waitForFinished(1000)) {
@@ -1977,22 +1984,6 @@ TextChannelMode Process::textChannelMode(Channel channel) const
return buffer->m_textChannelMode; return buffer->m_textChannelMode;
} }
void ProcessPrivate::slotTimeout()
{
if (!m_waitingForUser && (++m_hangTimerCount > m_maxHangTimerCount)) {
m_waitingForUser = true;
const bool terminate = !m_timeOutMessageBoxEnabled || askToKill(m_setup.m_commandLine);
m_waitingForUser = false;
if (terminate) {
q->stop();
q->waitForFinished();
m_result = ProcessResult::Hang;
} else {
m_hangTimerCount = 0;
}
}
}
void ProcessPrivate::handleStarted(qint64 processId, qint64 applicationMainThreadId) void ProcessPrivate::handleStarted(qint64 processId, qint64 applicationMainThreadId)
{ {
QTC_CHECK(m_state == QProcess::Starting); QTC_CHECK(m_state == QProcess::Starting);
@@ -2007,8 +1998,6 @@ void ProcessPrivate::handleReadyRead(const QByteArray &outputData, const QByteAr
{ {
QTC_CHECK(m_state == QProcess::Running); QTC_CHECK(m_state == QProcess::Running);
// TODO: check why we need this timer?
m_hangTimerCount = 0;
// TODO: store a copy of m_processChannelMode on start()? Currently we assert that state // TODO: store a copy of m_processChannelMode on start()? Currently we assert that state
// is NotRunning when setting the process channel mode. // is NotRunning when setting the process channel mode.
@@ -2062,8 +2051,6 @@ void ProcessPrivate::handleDone(const ProcessResultData &data)
else if (m_result != ProcessResult::Hang) else if (m_result != ProcessResult::Hang)
m_result = ProcessResult::StartFailed; m_result = ProcessResult::StartFailed;
m_hangTimerCount = 0;
if (m_resultData.m_error != QProcess::FailedToStart) { if (m_resultData.m_error != QProcess::FailedToStart) {
switch (m_resultData.m_exitStatus) { switch (m_resultData.m_exitStatus) {
case QProcess::NormalExit: case QProcess::NormalExit: