Skip to content

Commit 780800b

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 1ada9bf commit 780800b

File tree

1 file changed

+44
-0
lines changed

1 file changed

+44
-0
lines changed

compat/mingw.c

+44
Original file line numberDiff line numberDiff line change
@@ -1499,10 +1499,43 @@ struct pinfo_t {
14991499
static struct pinfo_t *pinfo = NULL;
15001500
CRITICAL_SECTION pinfo_cs;
15011501

1502+
#ifndef SIGRTMAX
1503+
#define SIGRTMAX 63
1504+
#endif
1505+
1506+
static void kill_child_processes_on_signal(void)
1507+
{
1508+
DWORD status;
1509+
1510+
/*
1511+
* Only continue if the process was terminated by a signal, as
1512+
* indicated by the exit status (128 + sig_no).
1513+
*
1514+
* As we are running in an atexit() handler, the exit code has been
1515+
* set at this stage by the ExitProcess() function already.
1516+
*/
1517+
if (!GetExitCodeProcess(GetCurrentProcess(), &status) ||
1518+
status <= 128 || status > 128 + SIGRTMAX)
1519+
return;
1520+
1521+
EnterCriticalSection(&pinfo_cs);
1522+
1523+
while (pinfo) {
1524+
struct pinfo_t *info = pinfo;
1525+
pinfo = pinfo->next;
1526+
exit_process(info->proc, status);
1527+
CloseHandle(info->proc);
1528+
free(info);
1529+
}
1530+
1531+
LeaveCriticalSection(&pinfo_cs);
1532+
}
1533+
15021534
static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
15031535
const char *dir,
15041536
int prepend_cmd, int fhin, int fhout, int fherr)
15051537
{
1538+
static int atexit_handler_initialized;
15061539
STARTUPINFOW si;
15071540
PROCESS_INFORMATION pi;
15081541
struct strbuf args;
@@ -1511,6 +1544,17 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
15111544
BOOL ret;
15121545
HANDLE cons;
15131546

1547+
if (!atexit_handler_initialized) {
1548+
atexit_handler_initialized = 1;
1549+
/*
1550+
* On Windows, there is no POSIX signaling. Instead, we inject
1551+
* a thread calling ExitProcess(128 + sig_no); and that calls
1552+
* the *atexit* handlers. Catch this condition and kill child
1553+
* processes with the same signal.
1554+
*/
1555+
atexit(kill_child_processes_on_signal);
1556+
}
1557+
15141558
do_unset_environment_variables();
15151559

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

0 commit comments

Comments
 (0)