@@ -10,6 +10,7 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
1010details. */
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+
361418extern " C" void
362419abort (void )
363420{
0 commit comments