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