From 1079fe9884ea50e04f8b90fca207d74aac987f3b Mon Sep 17 00:00:00 2001 From: eldritch horrors Date: Tue, 3 Feb 2026 00:27:40 +0100 Subject: [PATCH] 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 --- lix/libutil/processes.cc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lix/libutil/processes.cc b/lix/libutil/processes.cc index f25f5d41f..595bb2a59 100644 --- a/lix/libutil/processes.cc +++ b/lix/libutil/processes.cc @@ -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()); }