From 85547b0f0c608330f411863f688e8da61a22bb89 Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Sun, 19 Jan 2025 16:27:04 -0800 Subject: vmon: implement --reaper This adds minimal support for becoming a child subreaper. Exited orphans are handled correctly by being identified and ignored without triggering SIGCHLD snapshots nor exiting vmon. A subsequent commit will make vmon monitor itself as the root pid when reaper mode is active and vmon is parent of the command being executed, making it possible to observe any orphans vmon inherits as subreaper. --- src/vmon.c | 45 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/vmon.c b/src/vmon.c index 059bcd5..347d5d3 100644 --- a/src/vmon.c +++ b/src/vmon.c @@ -711,6 +711,13 @@ static vmon_t * vmon_startup(int argc, const char * const *argv) } } + if (vmon->reaper) { + if (prctl(PR_SET_CHILD_SUBREAPER, (unsigned long)1) < 0) { + VWM_ERROR("unable become child subreaper: %s", strerror(errno)); + goto _err_win; + } + } + return vmon; _err_win: @@ -919,20 +926,36 @@ int main(int argc, const char * const *argv) vmon->done = 1; } - if (got_sigchld) { - int status, r; - - if (vmon->snapshot && (r = vmon_snapshot(vmon)) < 0) - VWM_ERROR("error saving snapshot: %s", strerror(-r)); + while (got_sigchld) { + int status; + pid_t reaped; got_sigchld = 0; - wait(&status); - - if (WIFEXITED(status)) { - ret = WEXITSTATUS(status); + /* exhaustively collect statuses for all the exited children, if another + * sigchld gets delivered while we're doing this, we'll do it again, until + * that stops. + */ + while ((reaped = waitpid(-1, &status, WNOHANG)) > 0) { + int r; + + /* potential exited orphans if we're being subreaper, ignore those */ + if (reaped != vmon->pid) + continue; + + if (WIFEXITED(status) || WIFSIGNALED(status)) { + if (vmon->snapshot && (r = vmon_snapshot(vmon)) < 0) + VWM_ERROR("error saving snapshot: %s", strerror(-r)); + + ret = WEXITSTATUS(status); + + if (!vmon->linger) + vmon->done = 1; + } + } - if (!vmon->linger) - vmon->done = 1; + if (reaped < 0) { + VWM_ERROR("failed to waitpid on SIGCHLD: %s", strerror(errno)); + vmon->done = 1; } } -- cgit v1.2.3