From 493573b8799bb71c017f697149152def19196094 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 3 Jun 2022 14:28:30 +0200 Subject: [PATCH] QtcProcess: Make reaper timeout customizable Add a setter and getter for reaper timeout. This makes it possible to customize the timeout for the reaper after which it should call kill() when previous terminate() was unsuccessful. This setting is also used for QtcProcess::stop(). Change-Id: I653a3ad107ae4173bb8254c85cfc07886bf6a9c6 Reviewed-by: hjk --- src/libs/utils/launcherpackets.cpp | 6 ++++-- src/libs/utils/launcherpackets.h | 1 + src/libs/utils/launchersocket.cpp | 1 + src/libs/utils/processinterface.h | 1 + src/libs/utils/qtcprocess.cpp | 20 ++++++++++++++++--- src/libs/utils/qtcprocess.h | 5 ++++- src/libs/utils/terminalprocess.cpp | 1 + src/plugins/docker/dockerdevice.cpp | 1 + src/plugins/remotelinux/linuxdevice.cpp | 1 + .../processlauncher/launchersockethandler.cpp | 6 +++++- 10 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/libs/utils/launcherpackets.cpp b/src/libs/utils/launcherpackets.cpp index ee68a70b144..87a3656306a 100644 --- a/src/libs/utils/launcherpackets.cpp +++ b/src/libs/utils/launcherpackets.cpp @@ -69,7 +69,8 @@ void StartProcessPacket::doSerialize(QDataStream &stream) const << nativeArguments << lowPriority << unixTerminalDisabled - << useCtrlCStub; + << useCtrlCStub + << reaperTimeout; } void StartProcessPacket::doDeserialize(QDataStream &stream) @@ -88,7 +89,8 @@ void StartProcessPacket::doDeserialize(QDataStream &stream) >> nativeArguments >> lowPriority >> unixTerminalDisabled - >> useCtrlCStub; + >> useCtrlCStub + >> reaperTimeout; processMode = Utils::ProcessMode(processModeInt); processChannelMode = QProcess::ProcessChannelMode(processChannelModeInt); } diff --git a/src/libs/utils/launcherpackets.h b/src/libs/utils/launcherpackets.h index 2c4dad8d08b..066862ef796 100644 --- a/src/libs/utils/launcherpackets.h +++ b/src/libs/utils/launcherpackets.h @@ -119,6 +119,7 @@ public: bool lowPriority = false; bool unixTerminalDisabled = false; bool useCtrlCStub = false; + int reaperTimeout = 500; private: void doSerialize(QDataStream &stream) const override; diff --git a/src/libs/utils/launchersocket.cpp b/src/libs/utils/launchersocket.cpp index 1677fd892cc..fc8ea36042f 100644 --- a/src/libs/utils/launchersocket.cpp +++ b/src/libs/utils/launchersocket.cpp @@ -288,6 +288,7 @@ void CallerHandle::start(const QString &program, const QStringList &arguments) p.lowPriority = m_setup->m_lowPriority; p.unixTerminalDisabled = m_setup->m_unixTerminalDisabled; p.useCtrlCStub = m_setup->m_useCtrlCStub; + p.reaperTimeout = m_setup->m_reaperTimeout; sendPacket(p); } diff --git a/src/libs/utils/processinterface.h b/src/libs/utils/processinterface.h index 0295f92d0c1..1722a2c6849 100644 --- a/src/libs/utils/processinterface.h +++ b/src/libs/utils/processinterface.h @@ -54,6 +54,7 @@ public: QString m_standardInputFile; QString m_nativeArguments; // internal, dependent on specific code path + int m_reaperTimeout = 500; // in ms bool m_abortOnMetaChars = true; bool m_runAsRoot = false; bool m_lowPriority = false; diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 69cf99325bc..b8272f64ce5 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -340,7 +340,7 @@ public: emit readyRead({}, m_process->readAllStandardError()); }); } - ~QProcessImpl() final { ProcessReaper::reap(m_process); } + ~QProcessImpl() final { ProcessReaper::reap(m_process, m_setup.m_reaperTimeout); } private: qint64 write(const QByteArray &data) final { return m_process->write(data); } @@ -1166,6 +1166,16 @@ QVariantHash QtcProcess::extraData() const return d->m_setup.m_extraData; } +void QtcProcess::setReaperTimeout(int msecs) +{ + d->m_setup.m_reaperTimeout = msecs; +} + +int QtcProcess::reaperTimeout() const +{ + return d->m_setup.m_reaperTimeout; +} + void QtcProcess::setRemoteProcessHooks(const DeviceProcessHooks &hooks) { s_deviceHooks = hooks; @@ -1501,12 +1511,16 @@ void QtcProcess::close() d->clearForRun(); } -void QtcProcess::stop(int killTimeout) +/* + Calls terminate() directly and after a delay of reaperTimeout() it calls kill() + if the process is still running. +*/ +void QtcProcess::stop() { if (state() == QProcess::NotRunning) return; - d->sendControlSignal(ControlSignal::Terminate, killTimeout); + d->sendControlSignal(ControlSignal::Terminate, d->m_process->m_setup.m_reaperTimeout); } QString QtcProcess::locateBinary(const QString &binary) diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h index 7d2f39b1deb..15cc4693c3c 100644 --- a/src/libs/utils/qtcprocess.h +++ b/src/libs/utils/qtcprocess.h @@ -65,7 +65,7 @@ public: void interrupt(); void kickoffProcess(); void close(); - void stop(int killTimeout = 500); + void stop(); QByteArray readAllStandardOutput(); QByteArray readAllStandardError(); @@ -131,6 +131,9 @@ public: void setExtraData(const QVariantHash &extraData); QVariantHash extraData() const; + void setReaperTimeout(int msecs); + int reaperTimeout() const; + static void setRemoteProcessHooks(const DeviceProcessHooks &hooks); // TODO: Some usages of this method assume that Starting phase is also a running state diff --git a/src/libs/utils/terminalprocess.cpp b/src/libs/utils/terminalprocess.cpp index 8a37aeec5b0..a623191524d 100644 --- a/src/libs/utils/terminalprocess.cpp +++ b/src/libs/utils/terminalprocess.cpp @@ -411,6 +411,7 @@ void TerminalImpl::start() d->m_process.setEnvironment(m_setup.m_environment); d->m_process.setCommand({FilePath::fromString(terminal.command), allArgs}); d->m_process.setProcessImpl(m_setup.m_processImpl); + d->m_process.setReaperTimeout(m_setup.m_reaperTimeout); d->m_process.start(); if (!d->m_process.waitForStarted()) { const QString msg = tr("Cannot start the terminal emulator \"%1\", change the setting in the " diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 285b2f4cf6f..822007253ae 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -264,6 +264,7 @@ void DockerProcessImpl::start() m_process.setProcessImpl(m_setup.m_processImpl); m_process.setProcessMode(m_setup.m_processMode); m_process.setTerminalMode(m_setup.m_terminalMode); + m_process.setReaperTimeout(m_setup.m_reaperTimeout); m_process.setWriteData(m_setup.m_writeData); m_process.setProcessChannelMode(m_setup.m_processChannelMode); m_process.setExtraData(m_setup.m_extraData); diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 93b93ca416f..7f6dbb44586 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -738,6 +738,7 @@ void SshProcessInterfacePrivate::doStart() m_process.setProcessImpl(q->m_setup.m_processImpl); m_process.setProcessMode(q->m_setup.m_processMode); m_process.setTerminalMode(q->m_setup.m_terminalMode); + m_process.setReaperTimeout(q->m_setup.m_reaperTimeout); m_process.setWriteData(q->m_setup.m_writeData); // TODO: what about other fields from m_setup? SshParameters::setupSshEnvironment(&m_process); diff --git a/src/tools/processlauncher/launchersockethandler.cpp b/src/tools/processlauncher/launchersockethandler.cpp index 321f4688195..03ddb6528ff 100644 --- a/src/tools/processlauncher/launchersockethandler.cpp +++ b/src/tools/processlauncher/launchersockethandler.cpp @@ -44,9 +44,12 @@ public: ProcessHelper(parent), m_token(token) { } quintptr token() const { return m_token; } + void setReaperTimeout(int msecs) { m_reaperTimeout = msecs; }; + int reaperTimeout() const { return m_reaperTimeout; } private: const quintptr m_token; + int m_reaperTimeout = 500; }; LauncherSocketHandler::LauncherSocketHandler(QString serverPath, QObject *parent) @@ -208,6 +211,7 @@ void LauncherSocketHandler::handleStartPacket() if (packet.unixTerminalDisabled) process->setUnixTerminalDisabled(); process->setUseCtrlCStub(packet.useCtrlCStub); + process->setReaperTimeout(packet.reaperTimeout); process->start(packet.command, packet.arguments, handler->openMode()); handler->handleProcessStart(); } @@ -289,7 +293,7 @@ void LauncherSocketHandler::removeProcess(quintptr token) Process *process = it.value(); m_processes.erase(it); - ProcessReaper::reap(process); + ProcessReaper::reap(process, process->reaperTimeout()); } } // namespace Internal