libutil: kill process groups properly

we can have a ProcessGroup for a pid that *should* be a process group
but hasn't gotten around to setting its pgid yet. in such cases we do
want to be killing the thing anyway, not shoot into the void and hope
the right thing falls over. so far this has not been a problem due to
a mixture of just not having done this and being slow enough to work.

Change-Id: I4e0e54513252d8e18256b9286b819bfa957d70dc
This commit is contained in:
eldritch horrors
2026-02-03 14:51:01 +01:00
parent b8a9eaf1c8
commit 1079fe9884
+11 -2
View File
@@ -106,14 +106,23 @@ int ProcessGroup::kill()
debug("killing process group %1%", leader.get());
// send a kill signal to the leader *only* first. the leader we know may not have
// actually set its pgid yet, in which case the following kill for the group will
// fail. if this happens we still want to clean up the whole (hopefully singular)
// group, thus we start small. we will always attempt to kill the group too; only
// when we've waited on the pid we know can it be reused as a pgid. we are not in
// danger of killing any other processes we don't want to be killing as a result.
const auto leaderKillResult = ::kill(leader.get(), SIGKILL);
(void) leaderKillResult;
/* Send the requested signal to every process in the child
process group (which hopefully includes *all* its children). */
if (::kill(-leader.get(), SIGKILL) != 0) {
if (::kill(-leader.get(), SIGKILL) != 0 && errno != ESRCH) {
/* On BSDs, killing a process group will return EPERM if all
processes in the group are zombies (or something like
that). So try to detect and ignore that situation. */
#if __FreeBSD__ || __APPLE__
if (errno != EPERM || ::kill(leader.get(), 0) != 0)
if (errno != EPERM || leaderKillResult != 0)
#endif
logError(SysError("killing process group %d", leader.get()).info());
}