From b8c5d256646130067cc6f2d4db676dc2173522ac Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Fri, 16 Apr 2021 19:22:16 -0400 Subject: fix process_kill on windows --- main.c | 2 - process-win.c | 80 +++++++++++++++++++++++------------- windows_installer/ted/ted/ted.vdproj | 6 +-- 3 files changed, 55 insertions(+), 33 deletions(-) diff --git a/main.c b/main.c index 3a1b686..8cf3997 100644 --- a/main.c +++ b/main.c @@ -1,5 +1,3 @@ -// @TODO: -// - terminate process not working on windows? #include "base.h" no_warn_start #if _WIN32 diff --git a/process-win.c b/process-win.c index d36302b..d7ff4b2 100644 --- a/process-win.c +++ b/process-win.c @@ -2,6 +2,7 @@ struct Process { HANDLE pipe_read, pipe_write; + HANDLE job; PROCESS_INFORMATION process_info; char error[200]; }; @@ -15,7 +16,9 @@ static void get_last_error_str(char *out, size_t out_sz) { } bool process_run(Process *process, char const *command) { - // thanks to https://stackoverflow.com/a/35658917 + // thanks to https://stackoverflow.com/a/35658917 for the pipe code + // thanks to https://devblogs.microsoft.com/oldnewthing/20131209-00/?p=2433 for the job code + bool success = false; memset(process, 0, sizeof *process); char *command_line = str_dup(command); @@ -23,35 +26,57 @@ bool process_run(Process *process, char const *command) { strbuf_printf(process->error, "Out of memory."); return false; } - HANDLE pipe_read, pipe_write; - SECURITY_ATTRIBUTES security_attrs = {sizeof(SECURITY_ATTRIBUTES)}; - security_attrs.bInheritHandle = TRUE; - if (CreatePipe(&pipe_read, &pipe_write, &security_attrs, 0)) { - STARTUPINFOA startup = {sizeof(STARTUPINFOA)}; - startup.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; - startup.hStdOutput = pipe_write; - startup.hStdError = pipe_write; - startup.wShowWindow = SW_HIDE; - - if (CreateProcessA(NULL, command_line, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, - NULL, NULL, &startup, &process->process_info)) { - process->pipe_read = pipe_read; - process->pipe_write = pipe_write; - success = true; + // we need to create a "job" for this, because apparently when you kill a process on windows, + // all its children just keep going. so cmd.exe would die, but not the actual build process. + // jobs fix this, apparently. + HANDLE job = CreateJobObjectA(NULL, NULL); + if (job) { + JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info = {0}; + job_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + SetInformationJobObject(job, JobObjectExtendedLimitInformation, &job_info, sizeof job_info); + HANDLE pipe_read, pipe_write; + SECURITY_ATTRIBUTES security_attrs = {sizeof(SECURITY_ATTRIBUTES)}; + security_attrs.bInheritHandle = TRUE; + if (CreatePipe(&pipe_read, &pipe_write, &security_attrs, 0)) { + STARTUPINFOA startup = {sizeof(STARTUPINFOA)}; + startup.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; + startup.hStdOutput = pipe_write; + startup.hStdError = pipe_write; + startup.wShowWindow = SW_HIDE; + PROCESS_INFORMATION *process_info = &process->process_info; + if (CreateProcessA(NULL, command_line, NULL, NULL, TRUE, CREATE_NEW_CONSOLE | CREATE_SUSPENDED, + NULL, NULL, &startup, process_info)) { + // create a suspended process, add it to the job, then resume (unsuspend) the process + if (AssignProcessToJobObject(job, process_info->hProcess)) { + if (ResumeThread(process_info->hThread) != (DWORD)-1) { + process->job = job; + process->pipe_read = pipe_read; + process->pipe_write = pipe_write; + success = true; + } + } + if (!success) { + TerminateProcess(process_info->hProcess, 1); + CloseHandle(process_info->hProcess); + CloseHandle(process_info->hThread); + } + } else { + char buf[150]; + get_last_error_str(buf, sizeof buf); + strbuf_printf(process->error, "Couldn't run `%s`: %s", command, buf); + } + free(command_line); + if (!success) { + CloseHandle(pipe_read); + CloseHandle(pipe_write); + } } else { char buf[150]; get_last_error_str(buf, sizeof buf); - strbuf_printf(process->error, "Couldn't run `%s`: %s", command, buf); + strbuf_printf(process->error, "Couldn't create pipe: %s", buf); } - free(command_line); - if (!success) { - CloseHandle(pipe_read); - CloseHandle(pipe_write); - } - } else { - char buf[150]; - get_last_error_str(buf, sizeof buf); - strbuf_printf(process->error, "Couldn't create pipe: %s", buf); + if (!success) + CloseHandle(job); } return success; } @@ -78,8 +103,7 @@ long long process_read(Process *process, char *data, size_t size) { } void process_kill(Process *process) { - TerminateProcess(process->process_info.hProcess, 1); - TerminateThread(process->process_info.hThread, 1); + CloseHandle(process->job); CloseHandle(process->pipe_read); CloseHandle(process->pipe_write); CloseHandle(process->process_info.hProcess); diff --git a/windows_installer/ted/ted/ted.vdproj b/windows_installer/ted/ted/ted.vdproj index c2dba5e..960f7dd 100644 --- a/windows_installer/ted/ted/ted.vdproj +++ b/windows_installer/ted/ted/ted.vdproj @@ -505,15 +505,15 @@ { "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:ted" - "ProductCode" = "8:{E281ABEA-14D0-46C5-AFDB-BFF6F6617B3F}" - "PackageCode" = "8:{E3D40FEF-9758-436F-8B50-E63C8A309848}" + "ProductCode" = "8:{C8992411-A410-4770-BBCD-8FE8281C599B}" + "PackageCode" = "8:{E11A6787-F72C-47F3-9975-DF24587F89E3}" "UpgradeCode" = "8:{844F6C2B-DF3B-4A81-9BD5-603401BBA651}" "AspNetVersion" = "8:2.0.50727.0" "RestartWWWService" = "11:FALSE" "RemovePreviousVersions" = "11:TRUE" "DetectNewerInstalledVersion" = "11:FALSE" "InstallAllUsers" = "11:FALSE" - "ProductVersion" = "8:21.03.1809" + "ProductVersion" = "8:21.04.1619" "Manufacturer" = "8:ted" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:" -- cgit v1.2.3