diff --git a/compat/mingw.c b/compat/mingw.c index e68884cff2..56812dc4ce 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1432,10 +1432,44 @@ struct pinfo_t { static struct pinfo_t *pinfo = NULL; CRITICAL_SECTION pinfo_cs; +#ifndef SIGRTMAX +#define SIGRTMAX 63 +#endif + +static void kill_child_processes_on_signal(void) +{ + DWORD status; + + /* + * Only continue if the process was terminated by a signal, as + * indicated by the exit status (128 + sig_no). + * + * As we are running in an atexit() handler, the exit code has been + * set at this stage by the ExitProcess() function already. + */ + if (!GetExitCodeProcess(GetCurrentProcess(), &status) || + status <= 128 || status > 128 + SIGRTMAX) + return; + + EnterCriticalSection(&pinfo_cs); + + while (pinfo) { + struct pinfo_t *info = pinfo; + pinfo = pinfo->next; + if (exit_process(info->proc, status)) + /* the handle is still valid in case of error */ + CloseHandle(info->proc); + free(info); + } + + LeaveCriticalSection(&pinfo_cs); +} + static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv, const char *dir, int prepend_cmd, int fhin, int fhout, int fherr) { + static int atexit_handler_initialized; STARTUPINFOW si; PROCESS_INFORMATION pi; struct strbuf args; @@ -1445,6 +1479,17 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen HANDLE cons; const char *strace_env; + if (!atexit_handler_initialized) { + atexit_handler_initialized = 1; + /* + * On Windows, there is no POSIX signaling. Instead, we inject + * a thread calling ExitProcess(128 + sig_no); and that calls + * the *atexit* handlers. Catch this condition and kill child + * processes with the same signal. + */ + atexit(kill_child_processes_on_signal); + } + do_unset_environment_variables(); /* Determine whether or not we are associated to a console */