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.
|
// 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();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user