forked from qt-creator/qt-creator
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:
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
|
@@ -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();
|
||||||
|
@@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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()
|
||||||
{
|
{
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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();
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
|
@@ -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();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user