Skip to content

Commit f3aea9f

Browse files
committed
mingw: kill unterminated child processes on signals
Git for Windows' MSYS2 runtime was just adjusted to kill processes gently, by injecting a thread that calls ExitProcess(). In case of signals (such as when handling Ctrl+C in a MinTTY window), the exit code is 128 + sign_no, as expected by Git's source code. However, as there is no POSIX signal handling on Windows, no signal handlers are called. Instead, functions registered via atexit() are called. We work around that by testing the exit code explicitly. This fixes the Git for Windows side of the bug where interrupting `git clone https://...` would send the spawned-off `git remote-https` process into the background instead of interrupting it, i.e. the clone would continue and its progress would be reported mercilessly to the console window without the user being able to do anything about it (short of firing up the task manager and killing the appropriate task manually). Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 4adb44a commit f3aea9f

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

compat/mingw.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1459,10 +1459,44 @@ struct pinfo_t {
14591459
static struct pinfo_t *pinfo = NULL;
14601460
CRITICAL_SECTION pinfo_cs;
14611461

1462+
#ifndef SIGRTMAX
1463+
#define SIGRTMAX 63
1464+
#endif
1465+
1466+
static void kill_child_processes_on_signal(void)
1467+
{
1468+
DWORD status;
1469+
1470+
/*
1471+
* Only continue if the process was terminated by a signal, as
1472+
* indicated by the exit status (128 + sig_no).
1473+
*
1474+
* As we are running in an atexit() handler, the exit code has been
1475+
* set at this stage by the ExitProcess() function already.
1476+
*/
1477+
if (!GetExitCodeProcess(GetCurrentProcess(), &status) ||
1478+
status <= 128 || status > 128 + SIGRTMAX)
1479+
return;
1480+
1481+
EnterCriticalSection(&pinfo_cs);
1482+
1483+
while (pinfo) {
1484+
struct pinfo_t *info = pinfo;
1485+
pinfo = pinfo->next;
1486+
if (exit_process(info->proc, status))
1487+
/* the handle is still valid in case of error */
1488+
CloseHandle(info->proc);
1489+
free(info);
1490+
}
1491+
1492+
LeaveCriticalSection(&pinfo_cs);
1493+
}
1494+
14621495
static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
14631496
const char *dir,
14641497
int prepend_cmd, int fhin, int fhout, int fherr)
14651498
{
1499+
static int atexit_handler_initialized;
14661500
STARTUPINFOW si;
14671501
PROCESS_INFORMATION pi;
14681502
struct strbuf args;
@@ -1472,6 +1506,17 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
14721506
HANDLE cons;
14731507
const char *strace_env;
14741508

1509+
if (!atexit_handler_initialized) {
1510+
atexit_handler_initialized = 1;
1511+
/*
1512+
* On Windows, there is no POSIX signaling. Instead, we inject
1513+
* a thread calling ExitProcess(128 + sig_no); and that calls
1514+
* the *atexit* handlers. Catch this condition and kill child
1515+
* processes with the same signal.
1516+
*/
1517+
atexit(kill_child_processes_on_signal);
1518+
}
1519+
14751520
do_unset_environment_variables();
14761521

14771522
/* Determine whether or not we are associated to a console */

0 commit comments

Comments
 (0)