aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCristian Adam <cristian.adam@qt.io>2021-12-07 16:46:51 +0100
committerCristian Adam <cristian.adam@qt.io>2021-12-10 13:43:59 +0000
commit537ba23fff8cd2b3f2172042ecfba94484d55efb (patch)
tree703843b0a1477a4ae168b93ec72cc960033ac97d
parent922cce16345caa0e5323197d185cabe97b49f632 (diff)
process_ctrlc_stub: Close child process when parent closes
When using gui applications the closing of process_ctrlc_sub launcher application didn't have any effect on the child process. By using a job object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE the child process gets cancelled when parent process closes. Fixes: QTCREATORBUG-26687 Change-Id: Id13b4d6f876589a018fa8f6841304417b87ee653 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
-rw-r--r--src/libs/utils/process_ctrlc_stub.cpp47
1 files changed, 44 insertions, 3 deletions
diff --git a/src/libs/utils/process_ctrlc_stub.cpp b/src/libs/utils/process_ctrlc_stub.cpp
index 1c37adec3c..33694d6448 100644
--- a/src/libs/utils/process_ctrlc_stub.cpp
+++ b/src/libs/utils/process_ctrlc_stub.cpp
@@ -50,6 +50,40 @@
#define CALLBACK WINAPI
#endif
+/// Class that ensures that when the parent process cancels, the child
+/// process will also be cancelled by the operating system.
+///
+/// This allows handling of GUI applications that do not react to Ctrl+C
+/// or console applications that ignore Ctrl+C.
+class JobKillOnClose
+{
+ HANDLE m_job = nullptr;
+public:
+ JobKillOnClose()
+ {
+ m_job = CreateJobObject(nullptr, nullptr);
+ if (!m_job) {
+ fwprintf(stderr, L"qtcreator_ctrlc_stub: CreateJobObject failed: 0x%x.\n", GetLastError());
+ return;
+ }
+ JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {0};
+ jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+ if (!SetInformationJobObject(m_job, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli))) {
+ fwprintf(stderr, L"qtcreator_ctrlc_stub: SetInformationJobObject failed: 0x%x.\n", GetLastError());
+ }
+ }
+
+ BOOL AssignProcessToJob(HANDLE process) const
+ {
+ return AssignProcessToJobObject(m_job, process);
+ }
+
+ ~JobKillOnClose()
+ {
+ CloseHandle(m_job);
+ }
+};
+
const wchar_t szTitle[] = L"qtcctrlcstub";
const wchar_t szWindowClass[] = L"wcqtcctrlcstub";
const wchar_t szNice[] = L"-nice ";
@@ -61,7 +95,7 @@ LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
BOOL WINAPI shutdownHandler(DWORD dwCtrlType);
BOOL WINAPI interruptHandler(DWORD dwCtrlType);
bool isSpaceOrTab(const wchar_t c);
-bool startProcess(wchar_t pCommandLine[], bool lowerPriority);
+bool startProcess(wchar_t pCommandLine[], bool lowerPriority, const JobKillOnClose& job);
int main(int argc, char **)
{
@@ -108,7 +142,9 @@ int main(int argc, char **)
while (isSpaceOrTab(strCommandLine[++pos]))
;
}
- bool bSuccess = startProcess(strCommandLine + pos, lowerPriority);
+
+ JobKillOnClose job;
+ bool bSuccess = startProcess(strCommandLine + pos, lowerPriority, job);
free(strCommandLine);
if (!bSuccess)
@@ -181,7 +217,7 @@ DWORD WINAPI processWatcherThread(LPVOID lpParameter)
return 0;
}
-bool startProcess(wchar_t *pCommandLine, bool lowerPriority)
+bool startProcess(wchar_t *pCommandLine, bool lowerPriority, const JobKillOnClose& job)
{
SECURITY_ATTRIBUTES sa = {0};
sa.nLength = sizeof(sa);
@@ -199,6 +235,11 @@ bool startProcess(wchar_t *pCommandLine, bool lowerPriority)
}
CloseHandle(pi.hThread);
+ if (!job.AssignProcessToJob(pi.hProcess)) {
+ fwprintf(stderr, L"qtcreator_ctrlc_stub: AssignProcessToJobObject failed: 0x%x.\n", GetLastError());
+ return false;
+ }
+
HANDLE hThread = CreateThread(NULL, 0, processWatcherThread, reinterpret_cast<void*>(pi.hProcess), 0, NULL);
if (!hThread) {
fwprintf(stderr, L"qtcreator_ctrlc_stub: The watch dog thread cannot be started.\n");