forked from qt-creator/qt-creator
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>
This commit is contained in:
@@ -50,6 +50,40 @@
|
|||||||
#define CALLBACK WINAPI
|
#define CALLBACK WINAPI
|
||||||
#endif
|
#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 szTitle[] = L"qtcctrlcstub";
|
||||||
const wchar_t szWindowClass[] = L"wcqtcctrlcstub";
|
const wchar_t szWindowClass[] = L"wcqtcctrlcstub";
|
||||||
const wchar_t szNice[] = L"-nice ";
|
const wchar_t szNice[] = L"-nice ";
|
||||||
@@ -61,7 +95,7 @@ LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
|||||||
BOOL WINAPI shutdownHandler(DWORD dwCtrlType);
|
BOOL WINAPI shutdownHandler(DWORD dwCtrlType);
|
||||||
BOOL WINAPI interruptHandler(DWORD dwCtrlType);
|
BOOL WINAPI interruptHandler(DWORD dwCtrlType);
|
||||||
bool isSpaceOrTab(const wchar_t c);
|
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 **)
|
int main(int argc, char **)
|
||||||
{
|
{
|
||||||
@@ -108,7 +142,9 @@ int main(int argc, char **)
|
|||||||
while (isSpaceOrTab(strCommandLine[++pos]))
|
while (isSpaceOrTab(strCommandLine[++pos]))
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
bool bSuccess = startProcess(strCommandLine + pos, lowerPriority);
|
|
||||||
|
JobKillOnClose job;
|
||||||
|
bool bSuccess = startProcess(strCommandLine + pos, lowerPriority, job);
|
||||||
free(strCommandLine);
|
free(strCommandLine);
|
||||||
|
|
||||||
if (!bSuccess)
|
if (!bSuccess)
|
||||||
@@ -181,7 +217,7 @@ DWORD WINAPI processWatcherThread(LPVOID lpParameter)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool startProcess(wchar_t *pCommandLine, bool lowerPriority)
|
bool startProcess(wchar_t *pCommandLine, bool lowerPriority, const JobKillOnClose& job)
|
||||||
{
|
{
|
||||||
SECURITY_ATTRIBUTES sa = {0};
|
SECURITY_ATTRIBUTES sa = {0};
|
||||||
sa.nLength = sizeof(sa);
|
sa.nLength = sizeof(sa);
|
||||||
@@ -199,6 +235,11 @@ bool startProcess(wchar_t *pCommandLine, bool lowerPriority)
|
|||||||
}
|
}
|
||||||
CloseHandle(pi.hThread);
|
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);
|
HANDLE hThread = CreateThread(NULL, 0, processWatcherThread, reinterpret_cast<void*>(pi.hProcess), 0, NULL);
|
||||||
if (!hThread) {
|
if (!hThread) {
|
||||||
fwprintf(stderr, L"qtcreator_ctrlc_stub: The watch dog thread cannot be started.\n");
|
fwprintf(stderr, L"qtcreator_ctrlc_stub: The watch dog thread cannot be started.\n");
|
||||||
|
Reference in New Issue
Block a user