Skip to content

Commit

Permalink
Merge pull request git-for-windows#6 from dscho/ctrl-c
Browse files Browse the repository at this point in the history
When interrupting Win32 processes, kill their child processes, too
  • Loading branch information
dscho committed Nov 25, 2015
2 parents f87345a + 218a98a commit 62bfb1b
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 4 deletions.
1 change: 1 addition & 0 deletions winsup/cygwin/common-msys.din
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ sys_errlist = _sys_errlist DATA
sys_nerr = _sys_nerr DATA
sys_sigabbrev DATA
sys_siglist DATA
kill_process_tree DATA

# Exported functions
_Exit SIGFE
Expand Down
1 change: 1 addition & 0 deletions winsup/cygwin/common.din
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ sys_errlist = _sys_errlist DATA
sys_nerr = _sys_nerr DATA
sys_sigabbrev DATA
sys_siglist DATA
kill_process_tree DATA

# Exported functions
_Exit SIGFE
Expand Down
5 changes: 4 additions & 1 deletion winsup/cygwin/exceptions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1559,7 +1559,10 @@ sigpacket::process ()
if (have_execed)
{
sigproc_printf ("terminating captive process");
TerminateProcess (ch_spawn, sigExeced = si.si_signo);
if ((sigExeced = si.si_signo) == SIGINT)
kill_process_tree (GetProcessId (ch_spawn), sigExeced = si.si_signo);
else
TerminateProcess (ch_spawn, sigExeced = si.si_signo);
}
/* Dispatch to the appropriate function. */
sigproc_printf ("signal %d, signal handler %p", si.si_signo, handler);
Expand Down
2 changes: 2 additions & 0 deletions winsup/cygwin/include/cygwin/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -420,9 +420,11 @@ int siginterrupt (int, int);
#ifdef __INSIDE_CYGWIN__
extern const char *sys_sigabbrev[];
extern const char *sys_siglist[];
extern void kill_process_tree(pid_t pid, int sig);
#else
extern const char __declspec(dllimport) *sys_sigabbrev[];
extern const char __declspec(dllimport) *sys_siglist[];
extern void __declspec(dllimport) kill_process_tree(pid_t pid, int sig);
#endif

#ifdef __cplusplus
Expand Down
1 change: 1 addition & 0 deletions winsup/cygwin/include/cygwin/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ details. */
290: Add sysconf cache handling.
291: Export aligned_alloc, at_quick_exit, quick_exit.
292: Export rpmatch.
293: Export kill_process_tree.
*/

/* Note that we forgot to bump the api for ualarm, strtoll, strtoull,
Expand Down
57 changes: 57 additions & 0 deletions winsup/cygwin/signal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */

#include "winsup.h"
#include <tlhelp32.h>
#include <stdlib.h>
#include <sys/cygwin.h>
#include "pinfo.h"
Expand Down Expand Up @@ -361,6 +362,62 @@ killpg (pid_t pgrp, int sig)
return kill (-pgrp, sig);
}

/**
* Terminates the process corresponding to the process ID and all of its
* directly and indirectly spawned subprocesses.
*/
extern "C" void
kill_process_tree(pid_t pid, int sig)
{
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 entry;
DWORD pids[16384];
int max_len = sizeof(pids) / sizeof(*pids), i, len;

pids[0] = (DWORD) pid;
len = 1;

/*
* Even if Process32First()/Process32Next() seem to traverse the
* processes in topological order (i.e. parent processes before
* child processes), there is nothing in the Win32 API documentation
* suggesting that this is guaranteed.
*
* Therefore, run through them at least twice and stop when no more
* process IDs were added to the list.
*/
for (;;) {
int orig_len = len;

memset(&entry, 0, sizeof(entry));
entry.dwSize = sizeof(entry);

if (!Process32First(snapshot, &entry))
break;

do {
for (i = len - 1; i >= 0; i--) {
if (pids[i] == entry.th32ProcessID)
break;
if (pids[i] == entry.th32ParentProcessID)
pids[len++] = entry.th32ProcessID;
}
} while (len < max_len && Process32Next(snapshot, &entry));

if (orig_len == len || len >= max_len)
break;
}

for (i = len - 1; i >= 0; i--) {
HANDLE process = OpenProcess(PROCESS_TERMINATE, FALSE, pids[i]);

if (process) {
TerminateProcess(process, sig << 8);
CloseHandle(process);
}
}
}

extern "C" void
abort (void)
{
Expand Down
10 changes: 7 additions & 3 deletions winsup/utils/kill.cc
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,14 @@ forcekill (int pid, int sig, int wait)
return;
}
if (!wait || WaitForSingleObject (h, 200) != WAIT_OBJECT_0)
if (sig && !TerminateProcess (h, sig << 8)
&& WaitForSingleObject (h, 200) != WAIT_OBJECT_0)
fprintf (stderr, "%s: couldn't kill pid %u, %u\n",
{
if (sig == SIGINT || sig == SIGTERM)
kill_process_tree (dwpid, sig);
else if (sig && !TerminateProcess (h, sig << 8)
&& WaitForSingleObject (h, 200) != WAIT_OBJECT_0)
fprintf (stderr, "%s: couldn't kill pid %u, %u\n",
prog_name, (unsigned) dwpid, (unsigned int) GetLastError ());
}
CloseHandle (h);
}

Expand Down

0 comments on commit 62bfb1b

Please sign in to comment.