From b1609928eeea54578cd0cd18935110260cb23a11 Mon Sep 17 00:00:00 2001 From: srdusr <99972264+srdusr@users.noreply.github.com> Date: Mon, 10 Feb 2025 09:35:00 +0200 Subject: Reap spawned child processes instead of leaking zombies Every srd.spawn/Command::spawn call fires and forgets its Child handle by design (a compositor's main loop can't block waiting on an arbitrary launched command), but nothing else was reaping them either, so every one that exited stayed a zombie for the rest of the session. Confirmed live via an AGS peer session's own ps: six zombies from four different programs, spread across half an hour of ordinary use. Explicitly ignoring SIGCHLD is the standard fix for exactly this case -- the kernel reaps exited children itself, no waitpid loop needed. --- crates/srdwm/src/main.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/crates/srdwm/src/main.rs b/crates/srdwm/src/main.rs index 7e25fec..bb331dc 100644 --- a/crates/srdwm/src/main.rs +++ b/crates/srdwm/src/main.rs @@ -54,6 +54,22 @@ fn install_signal_handlers() { unsafe { libc::signal(libc::SIGTERM, handle_shutdown_signal as *const () as libc::sighandler_t); libc::signal(libc::SIGINT, handle_shutdown_signal as *const () as libc::sighandler_t); + // Every `srd.spawn(...)`/`std::process::Command::spawn` call in this + // codebase (`fn_spawn` in config/general.rs, scratchpad toggles, + // screenshot commands, XWayland's own child) fires the process and + // drops the `Child` handle without ever calling `.wait()` on it -- + // by design, since a compositor's main loop has no business + // blocking on an arbitrary spawned command. Nothing else was + // reaping them either, so every one that exited stayed a zombie for + // the rest of the session: confirmed live via an AGS peer session's + // own `ps`, six zombies (four different programs, half an hour + // apart) all parented to this process. Explicitly ignoring SIGCHLD + // is the standard POSIX fix for exactly "I spawn children I never + // wait() on and don't care about their exit status" - the kernel + // reaps them itself the instant they exit, no handler/waitpid loop + // needed. Harmless to XWayland's own child processes and to + // anything else this compositor ever spawns for the same reason. + libc::signal(libc::SIGCHLD, libc::SIG_IGN); } } -- cgit v1.2.3