From 8e3ada3f830ad0e7d3ddf4eaf2b16e695bd084e4 Mon Sep 17 00:00:00 2001 From: Andreas Reischuck Date: Thu, 6 Jul 2023 18:35:01 +0200 Subject: [PATCH] feat: Kill Windows compiler subprocess when ccache is aborted (#1274) --- src/execute.cpp | 86 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/src/execute.cpp b/src/execute.cpp index de684fd00..45b33ed12 100644 --- a/src/execute.cpp +++ b/src/execute.cpp @@ -105,6 +105,75 @@ win32execute(const char* path, int fd_stderr, const std::string& temp_dir) { + BOOL isProcessInJob; + DWORD dwCreationFlags = 0; + { + BOOL jobSuccess = + IsProcessInJob(GetCurrentProcess(), NULL, &isProcessInJob); + if (!jobSuccess) { + DWORD error = GetLastError(); + LOG("failed to IsProcessInJob: {} ({})", + Win32Util::error_message(error), + error); + return 0; + } + if (isProcessInJob) { + JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo = {}; + BOOL querySuccess = + QueryInformationJobObject(NULL, + JobObjectExtendedLimitInformation, + &jobInfo, + sizeof(jobInfo), + NULL); + if (!querySuccess) { + DWORD error = GetLastError(); + LOG("failed to QueryInformationJobObject: {} ({})", + Win32Util::error_message(error), + error); + return 0; + } + + bool isKillActive = (jobInfo.BasicLimitInformation.LimitFlags + & JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE); + bool allowBeakAway = (jobInfo.BasicLimitInformation.LimitFlags + & JOB_OBJECT_LIMIT_BREAKAWAY_OK); + if (!isKillActive && allowBeakAway) { + isProcessInJob = false; + dwCreationFlags = CREATE_BREAKAWAY_FROM_JOB | CREATE_SUSPENDED; + } + } else { + dwCreationFlags = CREATE_SUSPENDED; + } + } + HANDLE hJob = NULL; + if (!isProcessInJob) { + hJob = CreateJobObject(NULL, NULL); + if (hJob == NULL) { + DWORD error = GetLastError(); + LOG("failed to CreateJobObject: {} ({})", + Win32Util::error_message(error), + error); + return -1; + } + + { + // Set the job object to terminate all child processes when the parent + // process is killed + JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo = {}; + jobInfo.BasicLimitInformation.LimitFlags = + JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + BOOL jobSuccess = SetInformationJobObject( + hJob, JobObjectExtendedLimitInformation, &jobInfo, sizeof(jobInfo)); + if (!jobSuccess) { + DWORD error = GetLastError(); + LOG("failed to JobObjectExtendedLimitInformation: {} ({})", + Win32Util::error_message(error), + error); + return -1; + } + } + } + PROCESS_INFORMATION pi; memset(&pi, 0x00, sizeof(pi)); @@ -161,7 +230,7 @@ win32execute(const char* path, nullptr, nullptr, 1, - 0, + dwCreationFlags, nullptr, nullptr, &si, @@ -178,12 +247,27 @@ win32execute(const char* path, error); return -1; } + if (hJob) { + BOOL assignSuccess = AssignProcessToJobObject(hJob, pi.hProcess); + if (!assignSuccess) { + TerminateProcess(pi.hProcess, 1); + + DWORD error = GetLastError(); + LOG("failed to assign process to job object {}: {} ({})", + full_path, + Win32Util::error_message(error), + error); + return -1; + } + ResumeThread(pi.hThread); + } WaitForSingleObject(pi.hProcess, INFINITE); DWORD exitcode; GetExitCodeProcess(pi.hProcess, &exitcode); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); + CloseHandle(hJob); if (!doreturn) { exit(exitcode); } -- 2.47.2