Skip to content

Commit f338d12

Browse files
committed
Merge pull request git-for-windows#6 from dscho/ctrl-c
When interrupting Win32 processes, kill their child processes, too
2 parents 5aa0837 + 45fb356 commit f338d12

File tree

6 files changed

+73
-5
lines changed

6 files changed

+73
-5
lines changed

winsup/cygwin/common.din

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ sys_errlist = _sys_errlist DATA
3333
sys_nerr = _sys_nerr DATA
3434
sys_sigabbrev DATA
3535
sys_siglist DATA
36+
kill_process_tree DATA
3637

3738
# Exported functions
3839
_Exit SIGFE

winsup/cygwin/exceptions.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1547,7 +1547,10 @@ sigpacket::process ()
15471547
if (have_execed)
15481548
{
15491549
sigproc_printf ("terminating captive process");
1550-
TerminateProcess (ch_spawn, sigExeced = si.si_signo);
1550+
if ((sigExeced = si.si_signo) == SIGINT)
1551+
kill_process_tree (GetProcessId (ch_spawn), sigExeced = si.si_signo);
1552+
else
1553+
TerminateProcess (ch_spawn, sigExeced = si.si_signo);
15511554
}
15521555
/* Dispatch to the appropriate function. */
15531556
sigproc_printf ("signal %d, signal handler %p", si.si_signo, handler);

winsup/cygwin/include/cygwin/signal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,9 +410,11 @@ int siginterrupt (int, int);
410410
#ifdef __INSIDE_CYGWIN__
411411
extern const char *sys_sigabbrev[];
412412
extern const char *sys_siglist[];
413+
extern void kill_process_tree(pid_t pid, int sig);
413414
#else
414415
extern const char __declspec(dllimport) *sys_sigabbrev[];
415416
extern const char __declspec(dllimport) *sys_siglist[];
417+
extern void __declspec(dllimport) kill_process_tree(pid_t pid, int sig);
416418
#endif
417419

418420
#ifdef __cplusplus

winsup/cygwin/include/cygwin/version.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,12 +470,13 @@ details. */
470470
303: Export pthread_getname_np, pthread_setname_np.
471471
304: Export strerror_l, strptime_l, wcsftime_l.
472472
305: [f]pathconf flag _PC_CASE_INSENSITIVE added.
473+
306: Export kill_process_tree.
473474
474475
Note that we forgot to bump the api for ualarm, strtoll, strtoull,
475476
sigaltstack, sethostname. */
476477

477478
#define CYGWIN_VERSION_API_MAJOR 0
478-
#define CYGWIN_VERSION_API_MINOR 305
479+
#define CYGWIN_VERSION_API_MINOR 306
479480

480481
/* There is also a compatibity version number associated with the shared memory
481482
regions. It is incremented when incompatible changes are made to the shared

winsup/cygwin/signal.cc

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
1010
details. */
1111

1212
#include "winsup.h"
13+
#include <tlhelp32.h>
1314
#include <stdlib.h>
1415
#include <sys/cygwin.h>
1516
#include "pinfo.h"
@@ -358,6 +359,62 @@ killpg (pid_t pgrp, int sig)
358359
return kill (-pgrp, sig);
359360
}
360361

362+
/**
363+
* Terminates the process corresponding to the process ID and all of its
364+
* directly and indirectly spawned subprocesses.
365+
*/
366+
extern "C" void
367+
kill_process_tree(pid_t pid, int sig)
368+
{
369+
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
370+
PROCESSENTRY32 entry;
371+
DWORD pids[16384];
372+
int max_len = sizeof(pids) / sizeof(*pids), i, len;
373+
374+
pids[0] = (DWORD) pid;
375+
len = 1;
376+
377+
/*
378+
* Even if Process32First()/Process32Next() seem to traverse the
379+
* processes in topological order (i.e. parent processes before
380+
* child processes), there is nothing in the Win32 API documentation
381+
* suggesting that this is guaranteed.
382+
*
383+
* Therefore, run through them at least twice and stop when no more
384+
* process IDs were added to the list.
385+
*/
386+
for (;;) {
387+
int orig_len = len;
388+
389+
memset(&entry, 0, sizeof(entry));
390+
entry.dwSize = sizeof(entry);
391+
392+
if (!Process32First(snapshot, &entry))
393+
break;
394+
395+
do {
396+
for (i = len - 1; i >= 0; i--) {
397+
if (pids[i] == entry.th32ProcessID)
398+
break;
399+
if (pids[i] == entry.th32ParentProcessID)
400+
pids[len++] = entry.th32ProcessID;
401+
}
402+
} while (len < max_len && Process32Next(snapshot, &entry));
403+
404+
if (orig_len == len || len >= max_len)
405+
break;
406+
}
407+
408+
for (i = len - 1; i >= 0; i--) {
409+
HANDLE process = OpenProcess(PROCESS_TERMINATE, FALSE, pids[i]);
410+
411+
if (process) {
412+
TerminateProcess(process, sig << 8);
413+
CloseHandle(process);
414+
}
415+
}
416+
}
417+
361418
extern "C" void
362419
abort (void)
363420
{

winsup/utils/kill.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,10 +171,14 @@ forcekill (int pid, int sig, int wait)
171171
return;
172172
}
173173
if (!wait || WaitForSingleObject (h, 200) != WAIT_OBJECT_0)
174-
if (sig && !TerminateProcess (h, sig << 8)
175-
&& WaitForSingleObject (h, 200) != WAIT_OBJECT_0)
176-
fprintf (stderr, "%s: couldn't kill pid %u, %u\n",
174+
{
175+
if (sig == SIGINT || sig == SIGTERM)
176+
kill_process_tree (dwpid, sig);
177+
else if (sig && !TerminateProcess (h, sig << 8)
178+
&& WaitForSingleObject (h, 200) != WAIT_OBJECT_0)
179+
fprintf (stderr, "%s: couldn't kill pid %u, %u\n",
177180
prog_name, (unsigned) dwpid, (unsigned int) GetLastError ());
181+
}
178182
CloseHandle (h);
179183
}
180184

0 commit comments

Comments
 (0)