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.
|
// Called from caller's thread exclusively.
|
||||||
bool waitForSignal(int msecs, SignalType newSignal);
|
bool waitForSignal(int msecs, SignalType newSignal);
|
||||||
void moveToCallerThread();
|
void moveToCallerThread();
|
||||||
|
void startKillTimer(int killTimeout);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Called from caller's thread exclusively.
|
// Called from caller's thread exclusively.
|
||||||
@@ -563,6 +564,7 @@ private:
|
|||||||
void appendSignal(ProcessInterfaceSignal *newSignal);
|
void appendSignal(ProcessInterfaceSignal *newSignal);
|
||||||
|
|
||||||
QtcProcessPrivate *m_caller = nullptr;
|
QtcProcessPrivate *m_caller = nullptr;
|
||||||
|
QTimer m_killTimer;
|
||||||
QMutex m_mutex;
|
QMutex m_mutex;
|
||||||
QWaitCondition m_waitCondition;
|
QWaitCondition m_waitCondition;
|
||||||
};
|
};
|
||||||
@@ -655,8 +657,9 @@ public:
|
|||||||
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;
|
Qt::ConnectionType connectionType() const;
|
||||||
void sendControlSignal(ControlSignal controlSignal);
|
void sendControlSignal(ControlSignal controlSignal, int killTimeout = -1);
|
||||||
// Called from ProcessInterfaceHandler thread exclusively.
|
// Called from ProcessInterfaceHandler thread exclusively.
|
||||||
|
void kill();
|
||||||
void appendSignal(ProcessInterfaceSignal *launcherSignal);
|
void appendSignal(ProcessInterfaceSignal *launcherSignal);
|
||||||
|
|
||||||
mutable QMutex m_mutex;
|
mutable QMutex m_mutex;
|
||||||
@@ -686,6 +689,7 @@ public:
|
|||||||
ProcessInterfaceHandler::ProcessInterfaceHandler(QtcProcessPrivate *caller,
|
ProcessInterfaceHandler::ProcessInterfaceHandler(QtcProcessPrivate *caller,
|
||||||
ProcessInterface *process)
|
ProcessInterface *process)
|
||||||
: m_caller(caller)
|
: m_caller(caller)
|
||||||
|
, m_killTimer(this)
|
||||||
{
|
{
|
||||||
connect(process, &ProcessInterface::started,
|
connect(process, &ProcessInterface::started,
|
||||||
this, &ProcessInterfaceHandler::handleStarted);
|
this, &ProcessInterfaceHandler::handleStarted);
|
||||||
@@ -693,6 +697,8 @@ ProcessInterfaceHandler::ProcessInterfaceHandler(QtcProcessPrivate *caller,
|
|||||||
this, &ProcessInterfaceHandler::handleReadyRead);
|
this, &ProcessInterfaceHandler::handleReadyRead);
|
||||||
connect(process, &ProcessInterface::done,
|
connect(process, &ProcessInterface::done,
|
||||||
this, &ProcessInterfaceHandler::handleDone);
|
this, &ProcessInterfaceHandler::handleDone);
|
||||||
|
m_killTimer.setSingleShot(true);
|
||||||
|
connect(&m_killTimer, &QTimer::timeout, caller, &QtcProcessPrivate::kill, Qt::DirectConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called from caller's thread exclusively.
|
// Called from caller's thread exclusively.
|
||||||
@@ -716,7 +722,14 @@ bool ProcessInterfaceHandler::waitForSignal(int msecs, SignalType newSignal)
|
|||||||
void ProcessInterfaceHandler::moveToCallerThread()
|
void ProcessInterfaceHandler::moveToCallerThread()
|
||||||
{
|
{
|
||||||
QMetaObject::invokeMethod(this, [this] {
|
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.
|
// Called from caller's thread exclusively.
|
||||||
@@ -748,6 +761,7 @@ void ProcessInterfaceHandler::handleReadyRead(const QByteArray &outputData, cons
|
|||||||
// Called from ProcessInterfaceHandler thread exclusively
|
// Called from ProcessInterfaceHandler thread exclusively
|
||||||
void ProcessInterfaceHandler::handleDone(const ProcessResultData &data)
|
void ProcessInterfaceHandler::handleDone(const ProcessResultData &data)
|
||||||
{
|
{
|
||||||
|
m_killTimer.stop();
|
||||||
appendSignal(new DoneSignal(data));
|
appendSignal(new DoneSignal(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -843,17 +857,26 @@ Qt::ConnectionType QtcProcessPrivate::connectionType() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Called from caller's thread exclusively
|
// Called from caller's thread exclusively
|
||||||
void QtcProcessPrivate::sendControlSignal(ControlSignal controlSignal)
|
void QtcProcessPrivate::sendControlSignal(ControlSignal controlSignal, int killTimeout)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(QThread::currentThread() == thread(), return);
|
QTC_ASSERT(QThread::currentThread() == thread(), return);
|
||||||
if (!m_process || (m_state == QProcess::NotRunning))
|
if (!m_process || (m_state == QProcess::NotRunning))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QMetaObject::invokeMethod(m_process.get(), [this, controlSignal] {
|
QMetaObject::invokeMethod(m_process.get(), [this, controlSignal, killTimeout] {
|
||||||
m_process->sendControlSignal(controlSignal);
|
m_process->sendControlSignal(controlSignal);
|
||||||
|
if (killTimeout >= 0)
|
||||||
|
m_processHandler->startKillTimer(killTimeout);
|
||||||
}, connectionType());
|
}, 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.
|
// Called from ProcessInterfaceHandler thread exclusively.
|
||||||
void QtcProcessPrivate::appendSignal(ProcessInterfaceSignal *newSignal)
|
void QtcProcessPrivate::appendSignal(ProcessInterfaceSignal *newSignal)
|
||||||
{
|
{
|
||||||
@@ -1478,6 +1501,14 @@ void QtcProcess::close()
|
|||||||
d->clearForRun();
|
d->clearForRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QtcProcess::stop(int killTimeout)
|
||||||
|
{
|
||||||
|
if (state() == QProcess::NotRunning)
|
||||||
|
return;
|
||||||
|
|
||||||
|
d->sendControlSignal(ControlSignal::Terminate, killTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
QString QtcProcess::locateBinary(const QString &binary)
|
QString QtcProcess::locateBinary(const QString &binary)
|
||||||
{
|
{
|
||||||
const QByteArray path = qgetenv("PATH");
|
const QByteArray path = qgetenv("PATH");
|
||||||
|
@@ -65,6 +65,7 @@ public:
|
|||||||
void interrupt();
|
void interrupt();
|
||||||
void kickoffProcess();
|
void kickoffProcess();
|
||||||
void close();
|
void close();
|
||||||
|
void stop(int killTimeout = 500);
|
||||||
|
|
||||||
QByteArray readAllStandardOutput();
|
QByteArray readAllStandardOutput();
|
||||||
QByteArray readAllStandardError();
|
QByteArray readAllStandardError();
|
||||||
|
Reference in New Issue
Block a user