QtcProcess: Use generic waitFor...()

Task-number: QTCREATORBUG-27430
Change-Id: I34ecc8a5937204875c235eee285c32d9cb0a0a86
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Jarek Kobus
2022-04-25 20:47:09 +02:00
parent 221414c5e8
commit ece39c7c2f

View File

@@ -554,6 +554,7 @@ public:
// Called from caller's thread exclusively. // Called from caller's thread exclusively.
bool waitForSignal(int msecs, SignalType newSignal); bool waitForSignal(int msecs, SignalType newSignal);
void moveToCallerThread();
private: private:
// Called from caller's thread exclusively. // Called from caller's thread exclusively.
@@ -656,9 +657,12 @@ public:
// === ProcessInterfaceHandler related === // === ProcessInterfaceHandler related ===
// Called from caller's thread exclusively // Called from caller's thread exclusively
bool waitForSignal(int msecs, SignalType newSignal);
void flush() { flushFor(SignalType::NoSignal); } void flush() { flushFor(SignalType::NoSignal); }
bool flushFor(SignalType signalType); bool flushFor(SignalType signalType);
bool shouldFlush() const { QMutexLocker locker(&m_mutex); return !m_signals.isEmpty(); } bool shouldFlush() const { QMutexLocker locker(&m_mutex); return !m_signals.isEmpty(); }
Qt::ConnectionType connectionType() const;
void sendControlSignal(ControlSignal controlSignal);
// Called from ProcessInterfaceHandler thread exclusively. // Called from ProcessInterfaceHandler thread exclusively.
void appendSignal(ProcessInterfaceSignal *launcherSignal); void appendSignal(ProcessInterfaceSignal *launcherSignal);
@@ -725,6 +729,13 @@ bool ProcessInterfaceHandler::waitForSignal(int msecs, SignalType newSignal)
return false; return false;
} }
// Called from caller's thread exclusively.
void ProcessInterfaceHandler::moveToCallerThread()
{
QMetaObject::invokeMethod(this, [this] {
moveToThread(m_caller->thread()); }, Qt::BlockingQueuedConnection);
}
// Called from caller's thread exclusively. // Called from caller's thread exclusively.
bool ProcessInterfaceHandler::doWaitForSignal(QDeadlineTimer deadline) bool ProcessInterfaceHandler::doWaitForSignal(QDeadlineTimer deadline)
{ {
@@ -768,6 +779,26 @@ void ProcessInterfaceHandler::appendSignal(ProcessInterfaceSignal *newSignal)
QMetaObject::invokeMethod(m_caller, &QtcProcessPrivate::flush); QMetaObject::invokeMethod(m_caller, &QtcProcessPrivate::flush);
} }
// Called from caller's thread exclusively
bool QtcProcessPrivate::waitForSignal(int msecs, SignalType newSignal)
{
m_processHandler->setParent(nullptr);
QThread thread;
thread.start();
// Note: the thread may have started before and it's appending new signals before
// waitForSignal() is called. However, in this case they won't be flushed since
// the caller here is blocked, so all signals should be buffered and we are going
// to flush them from inside waitForSignal().
m_processHandler->moveToThread(&thread);
const bool result = m_processHandler->waitForSignal(msecs, newSignal);
m_processHandler->moveToCallerThread();
m_processHandler->setParent(this);
thread.quit();
thread.wait();
return result;
}
// Called from caller's thread exclusively // Called from caller's thread exclusively
bool QtcProcessPrivate::flushFor(SignalType signalType) bool QtcProcessPrivate::flushFor(SignalType signalType)
{ {
@@ -821,6 +852,25 @@ bool QtcProcessPrivate::flushFor(SignalType signalType)
return signalMatched; return signalMatched;
} }
// Called from caller's thread exclusively
Qt::ConnectionType QtcProcessPrivate::connectionType() const
{
return (m_process->thread() == thread()) ? Qt::DirectConnection
: Qt::BlockingQueuedConnection;
}
// Called from caller's thread exclusively
void QtcProcessPrivate::sendControlSignal(ControlSignal controlSignal)
{
QTC_ASSERT(QThread::currentThread() == thread(), return);
if (!m_process || (m_state == QProcess::NotRunning))
return;
QMetaObject::invokeMethod(m_process.get(), [this, controlSignal] {
m_process->sendControlSignal(controlSignal);
}, connectionType());
}
// Called from ProcessInterfaceHandler thread exclusively. // Called from ProcessInterfaceHandler thread exclusively.
void QtcProcessPrivate::appendSignal(ProcessInterfaceSignal *newSignal) void QtcProcessPrivate::appendSignal(ProcessInterfaceSignal *newSignal)
{ {
@@ -1073,26 +1123,22 @@ void QtcProcess::startImpl()
void QtcProcess::terminate() void QtcProcess::terminate()
{ {
if (d->m_process && (d->m_state != QProcess::NotRunning)) d->sendControlSignal(ControlSignal::Terminate);
d->m_process->sendControlSignal(ControlSignal::Terminate);
} }
void QtcProcess::kill() void QtcProcess::kill()
{ {
if (d->m_process && (d->m_state != QProcess::NotRunning)) d->sendControlSignal(ControlSignal::Kill);
d->m_process->sendControlSignal(ControlSignal::Kill);
} }
void QtcProcess::interrupt() void QtcProcess::interrupt()
{ {
if (d->m_process && (d->m_state != QProcess::NotRunning)) d->sendControlSignal(ControlSignal::Interrupt);
d->m_process->sendControlSignal(ControlSignal::Interrupt);
} }
void QtcProcess::kickoffProcess() void QtcProcess::kickoffProcess()
{ {
if (d->m_process && (d->m_state != QProcess::NotRunning)) d->sendControlSignal(ControlSignal::KickOff);
d->m_process->sendControlSignal(ControlSignal::KickOff);
} }
bool QtcProcess::startDetached(const CommandLine &cmd, const FilePath &workingDirectory, qint64 *pid) bool QtcProcess::startDetached(const CommandLine &cmd, const FilePath &workingDirectory, qint64 *pid)
@@ -1433,7 +1479,8 @@ bool QtcProcess::waitForStarted(int msecs)
return true; return true;
if (d->m_state == QProcess::NotRunning) if (d->m_state == QProcess::NotRunning)
return false; return false;
return s_waitForStarted.measureAndRun(&ProcessInterface::waitForStarted, d->m_process, msecs); return s_waitForStarted.measureAndRun(&QtcProcessPrivate::waitForSignal, d, msecs,
SignalType::Started);
} }
bool QtcProcess::waitForReadyRead(int msecs) bool QtcProcess::waitForReadyRead(int msecs)
@@ -1441,7 +1488,7 @@ bool QtcProcess::waitForReadyRead(int msecs)
QTC_ASSERT(d->m_process, return false); QTC_ASSERT(d->m_process, return false);
if (d->m_state == QProcess::NotRunning) if (d->m_state == QProcess::NotRunning)
return false; return false;
return d->m_process->waitForReadyRead(msecs); return d->waitForSignal(msecs, SignalType::ReadyRead);
} }
bool QtcProcess::waitForFinished(int msecs) bool QtcProcess::waitForFinished(int msecs)
@@ -1449,7 +1496,7 @@ bool QtcProcess::waitForFinished(int msecs)
QTC_ASSERT(d->m_process, return false); QTC_ASSERT(d->m_process, return false);
if (d->m_state == QProcess::NotRunning) if (d->m_state == QProcess::NotRunning)
return false; return false;
return d->m_process->waitForFinished(msecs); return d->waitForSignal(msecs, SignalType::Done);
} }
QByteArray QtcProcess::readAllStandardOutput() QByteArray QtcProcess::readAllStandardOutput()
@@ -1468,10 +1515,6 @@ QByteArray QtcProcess::readAllStandardError()
qint64 QtcProcess::write(const QString &input) qint64 QtcProcess::write(const QString &input)
{ {
QTC_ASSERT(processMode() == ProcessMode::Writer, return -1);
QTC_ASSERT(d->m_process, return -1);
QTC_ASSERT(state() == QProcess::Running, return -1);
// Non-windows is assumed to be UTF-8 // Non-windows is assumed to be UTF-8
if (commandLine().executable().osType() != OsTypeWindows) if (commandLine().executable().osType() != OsTypeWindows)
return writeRaw(input.toUtf8()); return writeRaw(input.toUtf8());
@@ -1487,12 +1530,23 @@ qint64 QtcProcess::write(const QString &input)
qint64 QtcProcess::writeRaw(const QByteArray &input) qint64 QtcProcess::writeRaw(const QByteArray &input)
{ {
return d->m_process->write(input); QTC_ASSERT(processMode() == ProcessMode::Writer, return -1);
QTC_ASSERT(d->m_process, return -1);
QTC_ASSERT(state() == QProcess::Running, return -1);
QTC_ASSERT(QThread::currentThread() == thread(), return -1);
qint64 result = -1;
QMetaObject::invokeMethod(d->m_process.get(), [this, input] {
d->m_process->write(input);
}, d->connectionType(), &result);
return result;
} }
void QtcProcess::close() void QtcProcess::close()
{ {
QTC_ASSERT(QThread::currentThread() == thread(), return);
if (d->m_process) { if (d->m_process) {
// Note: the m_process may be inside ProcessInterfaceHandler's thread.
QTC_ASSERT(d->m_process->thread() == thread(), return);
d->m_process->disconnect(); d->m_process->disconnect();
d->m_process.release()->deleteLater(); d->m_process.release()->deleteLater();
} }