ProcessInterface: Add sendControlSignal() method

It substitutes terminate, kill, interrupt and kickoffProcess
methods.

Task-number: QTCREATORBUG-27358
Change-Id: I9e952c2f4c1a7e76339366566f2c804a3df30347
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
Jarek Kobus
2022-04-11 19:45:04 +02:00
parent 25be242c6f
commit 7c8b5648fe
5 changed files with 80 additions and 71 deletions

View File

@@ -71,6 +71,13 @@ public:
QString m_errorString; QString m_errorString;
}; };
enum class ControlSignal {
Terminate,
Kill,
Interrupt,
KickOff
};
class QTCREATOR_UTILS_EXPORT ProcessInterface : public QObject class QTCREATOR_UTILS_EXPORT ProcessInterface : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -80,11 +87,8 @@ public:
ProcessInterface(ProcessSetupData::Ptr setup) : m_setup(setup) {} ProcessInterface(ProcessSetupData::Ptr setup) : m_setup(setup) {}
virtual void start() = 0; virtual void start() = 0;
virtual void interrupt() = 0;
virtual void terminate() = 0;
virtual void kill() = 0;
virtual qint64 write(const QByteArray &data) = 0; virtual qint64 write(const QByteArray &data) = 0;
virtual void sendControlSignal(ControlSignal controlSignal) = 0;
virtual QProcess::ProcessState state() const = 0; virtual QProcess::ProcessState state() const = 0;
@@ -92,8 +96,6 @@ public:
virtual bool waitForReadyRead(int msecs) = 0; virtual bool waitForReadyRead(int msecs) = 0;
virtual bool waitForFinished(int msecs) = 0; virtual bool waitForFinished(int msecs) = 0;
virtual void kickoffProcess();
signals: signals:
void started(qint64 processId, qint64 applicationMainThreadId = 0); void started(qint64 processId, qint64 applicationMainThreadId = 0);
void readyRead(const QByteArray &outputData, const QByteArray &errorData); void readyRead(const QByteArray &outputData, const QByteArray &errorData);
@@ -121,9 +123,6 @@ public:
} }
void start() override { m_target->start(); } void start() override { m_target->start(); }
void interrupt() override { m_target->interrupt(); }
void terminate() override { m_target->terminate(); }
void kill() override { m_target->kill(); }
qint64 write(const QByteArray &data) override { return m_target->write(data); } qint64 write(const QByteArray &data) override { return m_target->write(data); }
@@ -133,8 +132,6 @@ public:
bool waitForReadyRead(int msecs) override { return m_target->waitForReadyRead(msecs); } bool waitForReadyRead(int msecs) override { return m_target->waitForReadyRead(msecs); }
bool waitForFinished(int msecs) override { return m_target->waitForFinished(msecs); } bool waitForFinished(int msecs) override { return m_target->waitForFinished(msecs); }
void kickoffProcess() override { m_target->kickoffProcess(); }
protected: protected:
ProcessInterface *m_target; ProcessInterface *m_target;
}; };

View File

@@ -347,10 +347,23 @@ public:
} }
~QProcessImpl() final { ProcessReaper::reap(m_process); } ~QProcessImpl() final { ProcessReaper::reap(m_process); }
void interrupt() final { ProcessHelper::interruptProcess(m_process); }
void terminate() final { ProcessHelper::terminateProcess(m_process); }
void kill() final { m_process->kill(); }
qint64 write(const QByteArray &data) final { return m_process->write(data); } qint64 write(const QByteArray &data) final { return m_process->write(data); }
void sendControlSignal(ControlSignal controlSignal) final {
switch (controlSignal) {
case ControlSignal::Terminate:
ProcessHelper::terminateProcess(m_process);
break;
case ControlSignal::Kill:
m_process->kill();
break;
case ControlSignal::Interrupt:
ProcessHelper::interruptProcess(m_process);
break;
case ControlSignal::KickOff:
QTC_CHECK(false);
break;
}
}
QProcess::ProcessState state() const final { return m_process->state(); } QProcess::ProcessState state() const final { return m_process->state(); }
@@ -432,14 +445,24 @@ public:
m_handle = nullptr; m_handle = nullptr;
} }
void interrupt() final
{
if (m_setup->m_useCtrlCStub) // bypass launcher and interrupt directly
ProcessHelper::interruptPid(m_handle->processId());
}
void terminate() final { m_handle->terminate(); }
void kill() final { m_handle->kill(); }
qint64 write(const QByteArray &data) final { return m_handle->write(data); } qint64 write(const QByteArray &data) final { return m_handle->write(data); }
void sendControlSignal(ControlSignal controlSignal) final {
switch (controlSignal) {
case ControlSignal::Terminate:
m_handle->terminate();
break;
case ControlSignal::Kill:
m_handle->kill();
break;
case ControlSignal::Interrupt:
if (m_setup->m_useCtrlCStub) // bypass launcher and interrupt directly
ProcessHelper::interruptPid(m_handle->processId());
break;
case ControlSignal::KickOff:
QTC_CHECK(false);
break;
}
}
QProcess::ProcessState state() const final { return m_handle->state(); } QProcess::ProcessState state() const final { return m_handle->state(); }
@@ -599,11 +622,6 @@ ProcessResult QtcProcessPrivate::interpretExitCode(int exitCode)
} // Internal } // Internal
void ProcessInterface::kickoffProcess()
{
QTC_CHECK(false);
}
/*! /*!
\class Utils::QtcProcess \class Utils::QtcProcess
@@ -805,13 +823,25 @@ void QtcProcess::start()
void QtcProcess::terminate() void QtcProcess::terminate()
{ {
if (d->m_process) if (d->m_process)
d->m_process->terminate(); d->m_process->sendControlSignal(ControlSignal::Terminate);
}
void QtcProcess::kill()
{
if (d->m_process)
d->m_process->sendControlSignal(ControlSignal::Kill);
} }
void QtcProcess::interrupt() void QtcProcess::interrupt()
{ {
if (d->m_process) if (d->m_process)
d->m_process->interrupt(); d->m_process->sendControlSignal(ControlSignal::Interrupt);
}
void QtcProcess::kickoffProcess()
{
if (d->m_process)
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)
@@ -1115,12 +1145,6 @@ Environment QtcProcess::systemEnvironmentForBinary(const FilePath &filePath)
return Environment::systemEnvironment(); return Environment::systemEnvironment();
} }
void QtcProcess::kickoffProcess()
{
if (d->m_process)
d->m_process->kickoffProcess();
}
qint64 QtcProcess::applicationMainThreadId() const qint64 QtcProcess::applicationMainThreadId() const
{ {
return d->m_applicationMainThreadId; return d->m_applicationMainThreadId;
@@ -1181,12 +1205,6 @@ QByteArray QtcProcess::readAllStandardError()
return buf; return buf;
} }
void QtcProcess::kill()
{
if (d->m_process)
d->m_process->kill();
}
qint64 QtcProcess::write(const QByteArray &input) qint64 QtcProcess::write(const QByteArray &input)
{ {
QTC_ASSERT(processMode() == ProcessMode::Writer, return -1); QTC_ASSERT(processMode() == ProcessMode::Writer, return -1);

View File

@@ -60,9 +60,11 @@ public:
// ProcessInterface related // ProcessInterface related
virtual void start(); virtual void start();
virtual void interrupt();
virtual void terminate(); virtual void terminate();
virtual void kill(); virtual void kill();
virtual void interrupt();
void kickoffProcess();
void close(); void close();
virtual QByteArray readAllStandardOutput(); virtual QByteArray readAllStandardOutput();
@@ -70,6 +72,8 @@ public:
virtual qint64 write(const QByteArray &input); virtual qint64 write(const QByteArray &input);
virtual qint64 processId() const; virtual qint64 processId() const;
qint64 applicationMainThreadId() const;
virtual QProcess::ProcessState state() const; virtual QProcess::ProcessState state() const;
virtual ProcessResultData resultData() const; virtual ProcessResultData resultData() const;
@@ -83,9 +87,6 @@ public:
bool waitForReadyRead(int msecs = 30000); bool waitForReadyRead(int msecs = 30000);
bool waitForFinished(int msecs = 30000); bool waitForFinished(int msecs = 30000);
void kickoffProcess();
qint64 applicationMainThreadId() const;
// ProcessSetupData related // ProcessSetupData related
void setProcessImpl(ProcessImpl processImpl); void setProcessImpl(ProcessImpl processImpl);

View File

@@ -435,25 +435,29 @@ void TerminalImpl::cleanupAfterStartFailure(const QString &errorMessage)
d->m_tempFile = nullptr; d->m_tempFile = nullptr;
} }
void TerminalImpl::kickoffProcess() void TerminalImpl::sendControlSignal(ControlSignal controlSignal)
{ {
#ifdef Q_OS_WIN switch (controlSignal) {
// Not used. case Utils::ControlSignal::Terminate:
#else case Utils::ControlSignal::Kill:
if (d->m_stubSocket && d->m_stubSocket->isWritable()) { stopProcess();
d->m_stubSocket->write("c", 1); break;
d->m_stubSocket->flush(); case Utils::ControlSignal::Interrupt:
sendCommand('i');
break;
case Utils::ControlSignal::KickOff:
sendCommand('c');
break;
} }
#endif
} }
void TerminalImpl::interrupt() void TerminalImpl::sendCommand(char c)
{ {
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
// Not used. Q_UNUSED(c)
#else #else
if (d->m_stubSocket && d->m_stubSocket->isWritable()) { if (d->m_stubSocket && d->m_stubSocket->isWritable()) {
d->m_stubSocket->write("i", 1); d->m_stubSocket->write(&c, 1);
d->m_stubSocket->flush(); d->m_stubSocket->flush();
} }
#endif #endif
@@ -467,10 +471,7 @@ void TerminalImpl::killProcess()
cleanupInferior(); cleanupInferior();
} }
#else #else
if (d->m_stubSocket && d->m_stubSocket->isWritable()) { sendCommand('k');
d->m_stubSocket->write("k", 1);
d->m_stubSocket->flush();
}
#endif #endif
d->m_processId = 0; d->m_processId = 0;
} }
@@ -484,10 +485,7 @@ void TerminalImpl::killStub()
cleanupStub(); cleanupStub();
} }
#else #else
if (d->m_stubSocket && d->m_stubSocket->isWritable()) { sendCommand('s');
d->m_stubSocket->write("s", 1);
d->m_stubSocket->flush();
}
stubServerShutdown(); stubServerShutdown();
#endif #endif
} }

View File

@@ -45,10 +45,9 @@ public:
TerminalImpl(); TerminalImpl();
~TerminalImpl() final; ~TerminalImpl() final;
void start() final;
qint64 write(const QByteArray &) final { QTC_CHECK(false); return -1; } qint64 write(const QByteArray &) final { QTC_CHECK(false); return -1; }
void sendControlSignal(ControlSignal controlSignal) final;
void terminate() final { stopProcess(); }
void kill() final { stopProcess(); }
// intentionally no-op without an assert // intentionally no-op without an assert
bool waitForStarted(int) final { return false; } bool waitForStarted(int) final { return false; }
@@ -56,13 +55,8 @@ public:
// intentionally no-op without an assert // intentionally no-op without an assert
bool waitForFinished(int) final { return false; } bool waitForFinished(int) final { return false; }
void start() final;
QProcess::ProcessState state() const final; QProcess::ProcessState state() const final;
void kickoffProcess() final; // only debugger terminal, only non-windows
void interrupt() final; // only debugger terminal, only non-windows
private: private:
// OK, however, impl looks a bit different (!= NotRunning vs == Running). // OK, however, impl looks a bit different (!= NotRunning vs == Running).
// Most probably changing it into (== Running) should be OK. // Most probably changing it into (== Running) should be OK.
@@ -81,6 +75,7 @@ private:
void stubServerShutdown(); void stubServerShutdown();
void cleanupStub(); void cleanupStub();
void cleanupInferior(); void cleanupInferior();
void sendCommand(char c);
class TerminalProcessPrivate *d; class TerminalProcessPrivate *d;
}; };