forked from qt-creator/qt-creator
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:
@@ -554,6 +554,7 @@ public:
|
||||
|
||||
// Called from caller's thread exclusively.
|
||||
bool waitForSignal(int msecs, SignalType newSignal);
|
||||
void moveToCallerThread();
|
||||
|
||||
private:
|
||||
// Called from caller's thread exclusively.
|
||||
@@ -656,9 +657,12 @@ public:
|
||||
|
||||
// === ProcessInterfaceHandler related ===
|
||||
// Called from caller's thread exclusively
|
||||
bool waitForSignal(int msecs, SignalType newSignal);
|
||||
void flush() { flushFor(SignalType::NoSignal); }
|
||||
bool flushFor(SignalType signalType);
|
||||
bool shouldFlush() const { QMutexLocker locker(&m_mutex); return !m_signals.isEmpty(); }
|
||||
Qt::ConnectionType connectionType() const;
|
||||
void sendControlSignal(ControlSignal controlSignal);
|
||||
// Called from ProcessInterfaceHandler thread exclusively.
|
||||
void appendSignal(ProcessInterfaceSignal *launcherSignal);
|
||||
|
||||
@@ -725,6 +729,13 @@ bool ProcessInterfaceHandler::waitForSignal(int msecs, SignalType newSignal)
|
||||
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.
|
||||
bool ProcessInterfaceHandler::doWaitForSignal(QDeadlineTimer deadline)
|
||||
{
|
||||
@@ -768,6 +779,26 @@ void ProcessInterfaceHandler::appendSignal(ProcessInterfaceSignal *newSignal)
|
||||
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
|
||||
bool QtcProcessPrivate::flushFor(SignalType signalType)
|
||||
{
|
||||
@@ -821,6 +852,25 @@ bool QtcProcessPrivate::flushFor(SignalType signalType)
|
||||
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.
|
||||
void QtcProcessPrivate::appendSignal(ProcessInterfaceSignal *newSignal)
|
||||
{
|
||||
@@ -1073,26 +1123,22 @@ void QtcProcess::startImpl()
|
||||
|
||||
void QtcProcess::terminate()
|
||||
{
|
||||
if (d->m_process && (d->m_state != QProcess::NotRunning))
|
||||
d->m_process->sendControlSignal(ControlSignal::Terminate);
|
||||
d->sendControlSignal(ControlSignal::Terminate);
|
||||
}
|
||||
|
||||
void QtcProcess::kill()
|
||||
{
|
||||
if (d->m_process && (d->m_state != QProcess::NotRunning))
|
||||
d->m_process->sendControlSignal(ControlSignal::Kill);
|
||||
d->sendControlSignal(ControlSignal::Kill);
|
||||
}
|
||||
|
||||
void QtcProcess::interrupt()
|
||||
{
|
||||
if (d->m_process && (d->m_state != QProcess::NotRunning))
|
||||
d->m_process->sendControlSignal(ControlSignal::Interrupt);
|
||||
d->sendControlSignal(ControlSignal::Interrupt);
|
||||
}
|
||||
|
||||
void QtcProcess::kickoffProcess()
|
||||
{
|
||||
if (d->m_process && (d->m_state != QProcess::NotRunning))
|
||||
d->m_process->sendControlSignal(ControlSignal::KickOff);
|
||||
d->sendControlSignal(ControlSignal::KickOff);
|
||||
}
|
||||
|
||||
bool QtcProcess::startDetached(const CommandLine &cmd, const FilePath &workingDirectory, qint64 *pid)
|
||||
@@ -1433,7 +1479,8 @@ bool QtcProcess::waitForStarted(int msecs)
|
||||
return true;
|
||||
if (d->m_state == QProcess::NotRunning)
|
||||
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)
|
||||
@@ -1441,7 +1488,7 @@ bool QtcProcess::waitForReadyRead(int msecs)
|
||||
QTC_ASSERT(d->m_process, return false);
|
||||
if (d->m_state == QProcess::NotRunning)
|
||||
return false;
|
||||
return d->m_process->waitForReadyRead(msecs);
|
||||
return d->waitForSignal(msecs, SignalType::ReadyRead);
|
||||
}
|
||||
|
||||
bool QtcProcess::waitForFinished(int msecs)
|
||||
@@ -1449,7 +1496,7 @@ bool QtcProcess::waitForFinished(int msecs)
|
||||
QTC_ASSERT(d->m_process, return false);
|
||||
if (d->m_state == QProcess::NotRunning)
|
||||
return false;
|
||||
return d->m_process->waitForFinished(msecs);
|
||||
return d->waitForSignal(msecs, SignalType::Done);
|
||||
}
|
||||
|
||||
QByteArray QtcProcess::readAllStandardOutput()
|
||||
@@ -1468,10 +1515,6 @@ QByteArray QtcProcess::readAllStandardError()
|
||||
|
||||
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
|
||||
if (commandLine().executable().osType() != OsTypeWindows)
|
||||
return writeRaw(input.toUtf8());
|
||||
@@ -1487,12 +1530,23 @@ qint64 QtcProcess::write(const QString &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()
|
||||
{
|
||||
QTC_ASSERT(QThread::currentThread() == thread(), return);
|
||||
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.release()->deleteLater();
|
||||
}
|
||||
|
Reference in New Issue
Block a user