diff options
author | Cristian Adam <cristian.adam@qt.io> | 2021-12-07 16:46:51 +0100 |
---|---|---|
committer | Cristian Adam <cristian.adam@qt.io> | 2021-12-10 13:43:59 +0000 |
commit | 537ba23fff8cd2b3f2172042ecfba94484d55efb (patch) | |
tree | 703843b0a1477a4ae168b93ec72cc960033ac97d | |
parent | 922cce16345caa0e5323197d185cabe97b49f632 (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.cpp | 47 |
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"); |