ProcessReaper: Implement custom terminate for CtrlCStub case

Move CtrlCStub-specific interrupt into ProcessHelper.

Amends 7d7e4af3afb5ba9d0ed5210018dd6be67abda469

Change-Id: I5cd9a750c4a89587a874515f752b0144df4b8309
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Jarek Kobus
2022-03-14 17:02:11 +01:00
parent de1bef18e2
commit b76b8b1542
10 changed files with 106 additions and 54 deletions

View File

@@ -60,7 +60,7 @@ void StartProcessPacket::doSerialize(QDataStream &stream) const
{ {
stream << command << arguments << workingDir << env << int(processMode) << writeData stream << command << arguments << workingDir << env << int(processMode) << writeData
<< int(processChannelMode) << standardInputFile << belowNormalPriority << int(processChannelMode) << standardInputFile << belowNormalPriority
<< nativeArguments << lowPriority << unixTerminalDisabled; << nativeArguments << lowPriority << unixTerminalDisabled << useCtrlCStub;
} }
void StartProcessPacket::doDeserialize(QDataStream &stream) void StartProcessPacket::doDeserialize(QDataStream &stream)
@@ -68,7 +68,7 @@ void StartProcessPacket::doDeserialize(QDataStream &stream)
int cm, pm; int cm, pm;
stream >> command >> arguments >> workingDir >> env >> pm >> writeData >> cm stream >> command >> arguments >> workingDir >> env >> pm >> writeData >> cm
>> standardInputFile >> belowNormalPriority >> nativeArguments >> lowPriority >> standardInputFile >> belowNormalPriority >> nativeArguments >> lowPriority
>> unixTerminalDisabled; >> unixTerminalDisabled >> useCtrlCStub;
processChannelMode = QProcess::ProcessChannelMode(cm); processChannelMode = QProcess::ProcessChannelMode(cm);
processMode = Utils::ProcessMode(pm); processMode = Utils::ProcessMode(pm);
} }

View File

@@ -119,6 +119,7 @@ public:
QString nativeArguments; QString nativeArguments;
bool lowPriority = false; bool lowPriority = false;
bool unixTerminalDisabled = false; bool unixTerminalDisabled = false;
bool useCtrlCStub = false;
private: private:
void doSerialize(QDataStream &stream) const override; void doSerialize(QDataStream &stream) const override;

View File

@@ -402,6 +402,7 @@ void CallerHandle::start(const QString &program, const QStringList &arguments)
p->nativeArguments = m_setup->m_nativeArguments; p->nativeArguments = m_setup->m_nativeArguments;
p->lowPriority = m_setup->m_lowPriority; p->lowPriority = m_setup->m_lowPriority;
p->unixTerminalDisabled = m_setup->m_unixTerminalDisabled; p->unixTerminalDisabled = m_setup->m_unixTerminalDisabled;
p->useCtrlCStub = m_setup->m_useCtrlCStub;
m_startPacket.reset(p); m_startPacket.reset(p);
if (LauncherInterface::isReady()) if (LauncherInterface::isReady())
doStart(); doStart();

View File

@@ -60,7 +60,7 @@ public:
bool m_haveEnv = false; bool m_haveEnv = false;
bool m_lowPriority = false; bool m_lowPriority = false;
bool m_unixTerminalDisabled = false; bool m_unixTerminalDisabled = false;
bool m_useCtrlCStub = false; // debug only bool m_useCtrlCStub = false; // release only
bool m_belowNormalPriority = false; // internal, dependent on other fields and specific code path bool m_belowNormalPriority = false; // internal, dependent on other fields and specific code path
}; };

View File

@@ -24,6 +24,7 @@
****************************************************************************/ ****************************************************************************/
#include "processreaper.h" #include "processreaper.h"
#include "processutils.h"
#include "qtcassert.h" #include "qtcassert.h"
#include <QCoreApplication> #include <QCoreApplication>
@@ -116,8 +117,7 @@ signals:
private: private:
void terminate() void terminate()
{ {
// TODO: do a custom terminate here for ctrlCStub ProcessHelper::terminateProcess(m_reaperSetup.m_process);
m_reaperSetup.m_process->terminate();
QTimer::singleShot(m_reaperSetup.m_timeoutMs, this, &Reaper::handleTerminateTimeout); QTimer::singleShot(m_reaperSetup.m_timeoutMs, this, &Reaper::handleTerminateTimeout);
} }

View File

@@ -26,6 +26,9 @@
#include "processutils.h" #include "processutils.h"
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#ifdef QTCREATOR_PCH_H
#define CALLBACK WINAPI
#endif
#include <qt_windows.h> #include <qt_windows.h>
#else #else
#include <errno.h> #include <errno.h>
@@ -82,6 +85,79 @@ void ProcessStartHandler::setNativeArguments(const QString &arguments)
#endif // Q_OS_WIN #endif // Q_OS_WIN
} }
#ifdef Q_OS_WIN
static BOOL sendMessage(UINT message, HWND hwnd, LPARAM lParam)
{
DWORD dwProcessID;
GetWindowThreadProcessId(hwnd, &dwProcessID);
if ((DWORD)lParam == dwProcessID) {
SendNotifyMessage(hwnd, message, 0, 0);
return FALSE;
}
return TRUE;
}
BOOL CALLBACK sendShutDownMessageToAllWindowsOfProcess_enumWnd(HWND hwnd, LPARAM lParam)
{
static UINT uiShutDownMessage = RegisterWindowMessage(L"qtcctrlcstub_shutdown");
return sendMessage(uiShutDownMessage, hwnd, lParam);
}
BOOL CALLBACK sendInterruptMessageToAllWindowsOfProcess_enumWnd(HWND hwnd, LPARAM lParam)
{
static UINT uiInterruptMessage = RegisterWindowMessage(L"qtcctrlcstub_interrupt");
return sendMessage(uiInterruptMessage, hwnd, lParam);
}
#endif
void ProcessHelper::setUseCtrlCStub(bool enabled)
{
// Do not use the stub in debug mode. Activating the stub will shut down
// Qt Creator otherwise, because they share the same Windows console.
// See QTCREATORBUG-11995 for details.
#ifdef QT_DEBUG
Q_UNUSED(enabled)
#else
m_useCtrlCStub = enabled;
#endif
}
void ProcessHelper::terminateProcess()
{
#ifdef Q_OS_WIN
if (m_useCtrlCStub)
EnumWindows(sendShutDownMessageToAllWindowsOfProcess_enumWnd, processId());
else
terminate();
#else
terminate();
#endif
}
void ProcessHelper::terminateProcess(QProcess *process)
{
ProcessHelper *helper = qobject_cast<ProcessHelper *>(process);
if (helper)
helper->terminateProcess();
else
process->terminate();
}
void ProcessHelper::interruptPid(qint64 pid)
{
#ifdef Q_OS_WIN
EnumWindows(sendInterruptMessageToAllWindowsOfProcess_enumWnd, pid);
#else
Q_UNUSED(pid)
#endif
}
void ProcessHelper::interruptProcess(QProcess *process)
{
ProcessHelper *helper = qobject_cast<ProcessHelper *>(process);
if (helper && helper->m_useCtrlCStub)
ProcessHelper::interruptPid(process->processId());
}
void ProcessHelper::setupChildProcess_impl() void ProcessHelper::setupChildProcess_impl()
{ {

View File

@@ -26,6 +26,7 @@
#pragma once #pragma once
#include "processenums.h" #include "processenums.h"
#include "processreaper.h"
#include <QIODevice> #include <QIODevice>
#include <QProcess> #include <QProcess>
@@ -52,6 +53,8 @@ private:
class ProcessHelper : public QProcess class ProcessHelper : public QProcess
{ {
Q_OBJECT
public: public:
ProcessHelper(QObject *parent) : QProcess(parent), m_processStartHandler(this) ProcessHelper(QObject *parent) : QProcess(parent), m_processStartHandler(this)
{ {
@@ -70,11 +73,19 @@ public:
void setLowPriority() { m_lowPriority = true; } void setLowPriority() { m_lowPriority = true; }
void setUnixTerminalDisabled() { m_unixTerminalDisabled = true; } void setUnixTerminalDisabled() { m_unixTerminalDisabled = true; }
void setUseCtrlCStub(bool enabled); // release only
static void terminateProcess(QProcess *process);
static void interruptProcess(QProcess *process);
static void interruptPid(qint64 pid);
private: private:
void terminateProcess();
void setupChildProcess_impl(); void setupChildProcess_impl();
bool m_lowPriority = false; bool m_lowPriority = false;
bool m_unixTerminalDisabled = false; bool m_unixTerminalDisabled = false;
bool m_useCtrlCStub = false; // release only
ProcessStartHandler m_processStartHandler; ProcessStartHandler m_processStartHandler;
}; };

View File

@@ -59,13 +59,6 @@
#include <limits> #include <limits>
#include <memory> #include <memory>
#ifdef Q_OS_WIN
#ifdef QTCREATOR_PCH_H
#define CALLBACK WINAPI
#endif
#include <qt_windows.h>
#endif
using namespace Utils::Internal; using namespace Utils::Internal;
namespace Utils { namespace Utils {
@@ -412,9 +405,9 @@ public:
QByteArray readAllStandardError() override { return m_process->readAllStandardError(); } QByteArray readAllStandardError() override { return m_process->readAllStandardError(); }
void interrupt() override void interrupt() override
{ QTC_CHECK(false); } // TODO: provide default impl { ProcessHelper::interruptProcess(m_process); }
void terminate() override void terminate() override
{ m_process->terminate(); } { ProcessHelper::terminateProcess(m_process); }
void kill() override void kill() override
{ m_process->kill(); } { m_process->kill(); }
void close() override void close() override
@@ -462,6 +455,7 @@ private:
m_process->setLowPriority(); m_process->setLowPriority();
if (m_setup->m_unixTerminalDisabled) if (m_setup->m_unixTerminalDisabled)
m_process->setUnixTerminalDisabled(); m_process->setUnixTerminalDisabled();
m_process->setUseCtrlCStub(m_setup->m_useCtrlCStub);
m_process->start(program, arguments, handler->openMode()); m_process->start(program, arguments, handler->openMode());
handler->handleProcessStart(); handler->handleProcessStart();
} }
@@ -510,7 +504,10 @@ public:
QByteArray readAllStandardError() override { return m_handle->readAllStandardError(); } QByteArray readAllStandardError() override { return m_handle->readAllStandardError(); }
void interrupt() override void interrupt() override
{ QTC_CHECK(false); } // TODO: send it to process launcher and use there a default impl of QProcessImpl {
if (m_setup->m_useCtrlCStub) // bypass launcher and interrupt directly
ProcessHelper::interruptPid(processId());
}
void terminate() override { cancel(); } // TODO: what are differences among terminate, kill and close? void terminate() override { cancel(); } // TODO: what are differences among terminate, kill and close?
void kill() override { cancel(); } // TODO: see above void kill() override { cancel(); } // TODO: see above
void close() override { cancel(); } // TODO: see above void close() override { cancel(); } // TODO: see above
@@ -863,10 +860,10 @@ void QtcProcess::setUseCtrlCStub(bool enabled)
// Do not use the stub in debug mode. Activating the stub will shut down // Do not use the stub in debug mode. Activating the stub will shut down
// Qt Creator otherwise, because they share the same Windows console. // Qt Creator otherwise, because they share the same Windows console.
// See QTCREATORBUG-11995 for details. // See QTCREATORBUG-11995 for details.
#ifndef QT_DEBUG #ifdef QT_DEBUG
d->m_setup.m_useCtrlCStub = enabled;
#else
Q_UNUSED(enabled) Q_UNUSED(enabled)
#else
d->m_setup.m_useCtrlCStub = enabled;
#endif #endif
} }
@@ -900,49 +897,14 @@ void QtcProcess::start()
d->m_process->start(); d->m_process->start();
} }
#ifdef Q_OS_WIN
static BOOL sendMessage(UINT message, HWND hwnd, LPARAM lParam)
{
DWORD dwProcessID;
GetWindowThreadProcessId(hwnd, &dwProcessID);
if ((DWORD)lParam == dwProcessID) {
SendNotifyMessage(hwnd, message, 0, 0);
return FALSE;
}
return TRUE;
}
BOOL CALLBACK sendShutDownMessageToAllWindowsOfProcess_enumWnd(HWND hwnd, LPARAM lParam)
{
static UINT uiShutDownMessage = RegisterWindowMessage(L"qtcctrlcstub_shutdown");
return sendMessage(uiShutDownMessage, hwnd, lParam);
}
BOOL CALLBACK sendInterruptMessageToAllWindowsOfProcess_enumWnd(HWND hwnd, LPARAM lParam)
{
static UINT uiInterruptMessage = RegisterWindowMessage(L"qtcctrlcstub_interrupt");
return sendMessage(uiInterruptMessage, hwnd, lParam);
}
#endif
void QtcProcess::terminate() void QtcProcess::terminate()
{ {
#ifdef Q_OS_WIN
if (d->m_setup.m_useCtrlCStub)
EnumWindows(sendShutDownMessageToAllWindowsOfProcess_enumWnd, processId());
else
#endif
if (d->m_process) if (d->m_process)
d->m_process->terminate(); d->m_process->terminate();
} }
void QtcProcess::interrupt() void QtcProcess::interrupt()
{ {
#ifdef Q_OS_WIN
if (d->m_setup.m_useCtrlCStub)
EnumWindows(sendInterruptMessageToAllWindowsOfProcess_enumWnd, processId());
else
#endif
if (d->m_process) if (d->m_process)
d->m_process->interrupt(); d->m_process->interrupt();
} }

View File

@@ -111,7 +111,7 @@ public:
void setWriteData(const QByteArray &writeData); void setWriteData(const QByteArray &writeData);
void setUseCtrlCStub(bool enabled); // debug only void setUseCtrlCStub(bool enabled); // release only
void setLowPriority(); void setLowPriority();
void setDisableUnixTerminal(); void setDisableUnixTerminal();
void setRunAsRoot(bool on); void setRunAsRoot(bool on);

View File

@@ -216,6 +216,7 @@ void LauncherSocketHandler::handleStartPacket()
process->setLowPriority(); process->setLowPriority();
if (packet.unixTerminalDisabled) if (packet.unixTerminalDisabled)
process->setUnixTerminalDisabled(); process->setUnixTerminalDisabled();
process->setUseCtrlCStub(packet.useCtrlCStub);
process->start(packet.command, packet.arguments, handler->openMode()); process->start(packet.command, packet.arguments, handler->openMode());
handler->handleProcessStart(); handler->handleProcessStart();
} }