@@ -13,6 +13,7 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
1313details. */
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+
364421extern " C" void
365422abort (void )
366423{
0 commit comments