forked from qt-creator/qt-creator
QtcProcess: Add stop() method
This method works like close() with the difference that after calling stop() we are still going to receive signals from QtcProcess, especially done() signal. This method isn't blocking, so a calling it is fast. Just after calling this method QtcProcess is still in the same state and done() signal should be delivered asynchronously. It's safe to call waitForFinished() after calling stop() with the desired timeout. Calling stop() in a row with waitForFinished() is a good substitute for stopProcess(). Change-Id: I1df55beb7f89c9b73203c9ba4bc276a4060600a5 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -550,6 +550,7 @@ public:
|
||||
// Called from caller's thread exclusively.
|
||||
bool waitForSignal(int msecs, SignalType newSignal);
|
||||
void moveToCallerThread();
|
||||
void startKillTimer(int killTimeout);
|
||||
|
||||
private:
|
||||
// Called from caller's thread exclusively.
|
||||
@@ -563,6 +564,7 @@ private:
|
||||
void appendSignal(ProcessInterfaceSignal *newSignal);
|
||||
|
||||
QtcProcessPrivate *m_caller = nullptr;
|
||||
QTimer m_killTimer;
|
||||
QMutex m_mutex;
|
||||
QWaitCondition m_waitCondition;
|
||||
};
|
||||
@@ -655,8 +657,9 @@ public:
|
||||
bool flushFor(SignalType signalType);
|
||||
bool shouldFlush() const { QMutexLocker locker(&m_mutex); return !m_signals.isEmpty(); }
|
||||
Qt::ConnectionType connectionType() const;
|
||||
void sendControlSignal(ControlSignal controlSignal);
|
||||
void sendControlSignal(ControlSignal controlSignal, int killTimeout = -1);
|
||||
// Called from ProcessInterfaceHandler thread exclusively.
|
||||
void kill();
|
||||
void appendSignal(ProcessInterfaceSignal *launcherSignal);
|
||||
|
||||
mutable QMutex m_mutex;
|
||||
@@ -686,6 +689,7 @@ public:
|
||||
ProcessInterfaceHandler::ProcessInterfaceHandler(QtcProcessPrivate *caller,
|
||||
ProcessInterface *process)
|
||||
: m_caller(caller)
|
||||
, m_killTimer(this)
|
||||
{
|
||||
connect(process, &ProcessInterface::started,
|
||||
this, &ProcessInterfaceHandler::handleStarted);
|
||||
@@ -693,6 +697,8 @@ ProcessInterfaceHandler::ProcessInterfaceHandler(QtcProcessPrivate *caller,
|
||||
this, &ProcessInterfaceHandler::handleReadyRead);
|
||||
connect(process, &ProcessInterface::done,
|
||||
this, &ProcessInterfaceHandler::handleDone);
|
||||
m_killTimer.setSingleShot(true);
|
||||
connect(&m_killTimer, &QTimer::timeout, caller, &QtcProcessPrivate::kill, Qt::DirectConnection);
|
||||
}
|
||||
|
||||
// Called from caller's thread exclusively.
|
||||
@@ -716,7 +722,14 @@ bool ProcessInterfaceHandler::waitForSignal(int msecs, SignalType newSignal)
|
||||
void ProcessInterfaceHandler::moveToCallerThread()
|
||||
{
|
||||
QMetaObject::invokeMethod(this, [this] {
|
||||
moveToThread(m_caller->thread()); }, Qt::BlockingQueuedConnection);
|
||||
moveToThread(m_caller->thread());
|
||||
}, Qt::BlockingQueuedConnection);
|
||||
}
|
||||
|
||||
void ProcessInterfaceHandler::startKillTimer(int killTimeout)
|
||||
{
|
||||
m_killTimer.setInterval(killTimeout);
|
||||
m_killTimer.start();
|
||||
}
|
||||
|
||||
// Called from caller's thread exclusively.
|
||||
@@ -748,6 +761,7 @@ void ProcessInterfaceHandler::handleReadyRead(const QByteArray &outputData, cons
|
||||
// Called from ProcessInterfaceHandler thread exclusively
|
||||
void ProcessInterfaceHandler::handleDone(const ProcessResultData &data)
|
||||
{
|
||||
m_killTimer.stop();
|
||||
appendSignal(new DoneSignal(data));
|
||||
}
|
||||
|
||||
@@ -843,17 +857,26 @@ Qt::ConnectionType QtcProcessPrivate::connectionType() const
|
||||
}
|
||||
|
||||
// Called from caller's thread exclusively
|
||||
void QtcProcessPrivate::sendControlSignal(ControlSignal controlSignal)
|
||||
void QtcProcessPrivate::sendControlSignal(ControlSignal controlSignal, int killTimeout)
|
||||
{
|
||||
QTC_ASSERT(QThread::currentThread() == thread(), return);
|
||||
if (!m_process || (m_state == QProcess::NotRunning))
|
||||
return;
|
||||
|
||||
QMetaObject::invokeMethod(m_process.get(), [this, controlSignal] {
|
||||
QMetaObject::invokeMethod(m_process.get(), [this, controlSignal, killTimeout] {
|
||||
m_process->sendControlSignal(controlSignal);
|
||||
if (killTimeout >= 0)
|
||||
m_processHandler->startKillTimer(killTimeout);
|
||||
}, connectionType());
|
||||
}
|
||||
|
||||
// Called from ProcessInterfaceHandler thread exclusively.
|
||||
void QtcProcessPrivate::kill()
|
||||
{
|
||||
QTC_ASSERT(QThread::currentThread() == m_process->thread(), return);
|
||||
m_process->sendControlSignal(ControlSignal::Kill);
|
||||
}
|
||||
|
||||
// Called from ProcessInterfaceHandler thread exclusively.
|
||||
void QtcProcessPrivate::appendSignal(ProcessInterfaceSignal *newSignal)
|
||||
{
|
||||
@@ -1478,6 +1501,14 @@ void QtcProcess::close()
|
||||
d->clearForRun();
|
||||
}
|
||||
|
||||
void QtcProcess::stop(int killTimeout)
|
||||
{
|
||||
if (state() == QProcess::NotRunning)
|
||||
return;
|
||||
|
||||
d->sendControlSignal(ControlSignal::Terminate, killTimeout);
|
||||
}
|
||||
|
||||
QString QtcProcess::locateBinary(const QString &binary)
|
||||
{
|
||||
const QByteArray path = qgetenv("PATH");
|
||||
|
@@ -65,6 +65,7 @@ public:
|
||||
void interrupt();
|
||||
void kickoffProcess();
|
||||
void close();
|
||||
void stop(int killTimeout = 500);
|
||||
|
||||
QByteArray readAllStandardOutput();
|
||||
QByteArray readAllStandardError();
|
||||
|
Reference in New Issue
Block a user