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 Apr 2, 2017
2 parents 279a1c1 + 24351cc commit db68342
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 5 deletions.
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 @@ -1547,7 +1547,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 @@ -410,9 +410,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
3 changes: 2 additions & 1 deletion winsup/cygwin/include/cygwin/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -474,12 +474,13 @@ details. */
307: Export timingsafe_bcmp, timingsafe_memcmp.
308: Export dladdr.
309: Export getloadavg.
310: Export kill_process_tree.
Note that we forgot to bump the api for ualarm, strtoll, strtoull,
sigaltstack, sethostname. */

#define CYGWIN_VERSION_API_MAJOR 0
#define CYGWIN_VERSION_API_MINOR 309
#define CYGWIN_VERSION_API_MINOR 310

/* There is also a compatibity version number associated with the shared memory
regions. It is incremented when incompatible changes are made to the shared
Expand Down
57 changes: 57 additions & 0 deletions winsup/cygwin/signal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,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 @@ -358,6 +359,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 @@ -171,10 +171,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 db68342

Please sign in to comment.