Skip to content

Commit 2b28d3e

Browse files
committed
Merge pull request #6 from dscho/ctrl-c
When interrupting Win32 processes, kill their child processes, too
2 parents 6ee34cc + e8c4047 commit 2b28d3e

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
@@ -1559,7 +1559,10 @@ sigpacket::process ()
15591559
if (have_execed)
15601560
{
15611561
sigproc_printf ("terminating captive process");
1562-
TerminateProcess (ch_spawn, sigExeced = si.si_signo);
1562+
if ((sigExeced = si.si_signo) == SIGINT)
1563+
kill_process_tree (GetProcessId (ch_spawn), sigExeced = si.si_signo);
1564+
else
1565+
TerminateProcess (ch_spawn, sigExeced = si.si_signo);
15631566
}
15641567
/* Dispatch to the appropriate function. */
15651568
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
@@ -413,9 +413,11 @@ int siginterrupt (int, int);
413413
#ifdef __INSIDE_CYGWIN__
414414
extern const char *sys_sigabbrev[];
415415
extern const char *sys_siglist[];
416+
extern void kill_process_tree(pid_t pid, int sig);
416417
#else
417418
extern const char __declspec(dllimport) *sys_sigabbrev[];
418419
extern const char __declspec(dllimport) *sys_siglist[];
420+
extern void __declspec(dllimport) kill_process_tree(pid_t pid, int sig);
419421
#endif
420422

421423
#ifdef __cplusplus

winsup/cygwin/include/cygwin/version.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,13 +489,14 @@ details. */
489489
nexttowardf, nexttowardl, pow10l, powl, remainderl, remquol, roundl,
490490
scalbl, scalblnl, scalbnl, sincosl, sinhl, sinl, tanhl, tanl,
491491
tgammal, truncl.
492+
298: Export kill_process_tree.
492493
*/
493494

494495
/* Note that we forgot to bump the api for ualarm, strtoll, strtoull,
495496
sigaltstack, sethostname. */
496497

497498
#define CYGWIN_VERSION_API_MAJOR 0
498-
#define CYGWIN_VERSION_API_MINOR 297
499+
#define CYGWIN_VERSION_API_MINOR 298
499500

500501
/* There is also a compatibity version number associated with the
501502
shared memory regions. It is incremented when incompatible

winsup/cygwin/signal.cc

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

1515
#include "winsup.h"
16+
#include <tlhelp32.h>
1617
#include <stdlib.h>
1718
#include <sys/cygwin.h>
1819
#include "pinfo.h"
@@ -361,6 +362,62 @@ killpg (pid_t pgrp, int sig)
361362
return kill (-pgrp, sig);
362363
}
363364

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

winsup/utils/kill.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,14 @@ forcekill (int pid, int sig, int wait)
174174
return;
175175
}
176176
if (!wait || WaitForSingleObject (h, 200) != WAIT_OBJECT_0)
177-
if (sig && !TerminateProcess (h, sig << 8)
178-
&& WaitForSingleObject (h, 200) != WAIT_OBJECT_0)
179-
fprintf (stderr, "%s: couldn't kill pid %u, %u\n",
177+
{
178+
if (sig == SIGINT || sig == SIGTERM)
179+
kill_process_tree (dwpid, sig);
180+
else if (sig && !TerminateProcess (h, sig << 8)
181+
&& WaitForSingleObject (h, 200) != WAIT_OBJECT_0)
182+
fprintf (stderr, "%s: couldn't kill pid %u, %u\n",
180183
prog_name, (unsigned) dwpid, (unsigned int) GetLastError ());
184+
}
181185
CloseHandle (h);
182186
}
183187

0 commit comments

Comments
 (0)