killTree static method
Terminates pid's whole process tree (issue #517): the process group
when the job is its own group leader (one signal — also covers
children forked while the kill runs), otherwise a live ps descendant
walk; Windows delegates to taskkill /T. TERM first, a short grace,
then KILL. Best-effort: never throws.
Implementation
static Future<void> killTree(int pid, {required bool ownGroup}) async {
try {
if (Platform.isWindows) {
await Process.run('taskkill', ['/PID', '$pid', '/T', '/F']);
return;
}
if (ownGroup) {
Process.killPid(-pid, ProcessSignal.sigterm);
await Future<void>.delayed(_killGrace);
Process.killPid(-pid, ProcessSignal.sigkill);
return;
}
// No group leadership on this host (no setsid): walk the live tree.
var victims = await _descendantsOf(pid);
if (victims.isEmpty) return;
await _signalAll(victims, ProcessSignal.sigterm);
await Future<void>.delayed(_killGrace);
// Children may have been forked while the first round landed; the
// walk only roots at a still-observable pid, so a recycled root can
// never widen the victim set.
victims = await _descendantsOf(pid);
await _signalAll(victims, ProcessSignal.sigkill);
} on Object {
// Best-effort: stop() still backstops the direct child.
}
}