Utils: Allow graceful termination of reaped processes

Utils::Internal::Reaper class is doing graceful termination of
process. It tries in a loop to first terminate() then kill()
the process and at the end delete the object.

Utils::ProcessReapder::reap should not kill the process directly,
and now that the function works with a QProcess, the special
handling of QtcProcess::terminat() of qtcreator_ctrlc_stub.exe
processes needs to be handled explicitly.

Amends ace765c199

Fixes: QTCREATORBUG-26612
Change-Id: Ia109ec0737a8c605a84e93b6ee3691d843ed5da8
Reviewed-by: David Schulz <david.schulz@qt.io>
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Cristian Adam
2021-11-25 20:19:15 +01:00
parent 0f4a203337
commit 102d5fe46c
2 changed files with 37 additions and 5 deletions

View File

@@ -31,6 +31,13 @@
#include <QThread> #include <QThread>
#include <QTimer> #include <QTimer>
#ifdef Q_OS_WIN
#ifdef QTCREATOR_PCH_H
#define CALLBACK WINAPI
#endif
#include <qt_windows.h>
#endif
using namespace Utils; using namespace Utils;
namespace Utils { namespace Utils {
@@ -83,6 +90,26 @@ bool Reaper::isFinished() const
return !m_process; return !m_process;
} }
#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);
}
#endif
void Reaper::nextIteration() void Reaper::nextIteration()
{ {
QProcess::ProcessState state = m_process ? m_process->state() : QProcess::NotRunning; QProcess::ProcessState state = m_process ? m_process->state() : QProcess::NotRunning;
@@ -96,11 +123,16 @@ void Reaper::nextIteration()
if (m_lastState == QProcess::Starting) if (m_lastState == QProcess::Starting)
m_process->kill(); m_process->kill();
} else if (state == QProcess::Running) { } else if (state == QProcess::Running) {
if (m_lastState == QProcess::Running) if (m_lastState == QProcess::Running) {
m_process->kill(); m_process->kill();
else } else if (m_process->program().endsWith(QLatin1String("qtcreator_ctrlc_stub.exe"))) {
#ifdef Q_OS_WIN
EnumWindows(sendShutDownMessageToAllWindowsOfProcess_enumWnd, m_process->processId());
#endif
} else {
m_process->terminate(); m_process->terminate();
} }
}
m_lastState = state; m_lastState = state;
m_iterationTimer.start(); m_iterationTimer.start();
@@ -149,10 +181,7 @@ void ProcessReaper::reap(QProcess *process, int timeoutMs)
if (process->state() == QProcess::NotRunning) { if (process->state() == QProcess::NotRunning) {
process->deleteLater(); process->deleteLater();
return; return;
} else {
process->kill();
} }
// Neither can move object with a parent into a different thread // Neither can move object with a parent into a different thread
// nor reaping the process with a parent makes any sense. // nor reaping the process with a parent makes any sense.
process->setParent(nullptr); process->setParent(nullptr);

View File

@@ -8,6 +8,9 @@ QtcTool {
cpp.defines: base.concat("QTCREATOR_UTILS_STATIC_LIB") cpp.defines: base.concat("QTCREATOR_UTILS_STATIC_LIB")
cpp.includePaths: base.concat(pathToUtils) cpp.includePaths: base.concat(pathToUtils)
cpp.dynamicLibraries: [
"user32",
]
files: [ files: [
"launcherlogging.cpp", "launcherlogging.cpp",