diff --git a/Cargo.lock b/Cargo.lock index e7678a62..41ece0ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4088,6 +4088,7 @@ dependencies = [ "futures", "homedir", "ignore", + "libc", "libsqlite3-sys", "matrix-sdk", "mime_guess", diff --git a/Cargo.toml b/Cargo.toml index 1adad894..b3263f9f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,3 +40,4 @@ pulldown-cmark = { version = "0.13.3", default-features = false, features = [ "html", ] } regex = "1" +libc = "0.2" diff --git a/server/Cargo.toml b/server/Cargo.toml index 1b51db48..bb3608b7 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -38,6 +38,9 @@ regex = { workspace = true } libsqlite3-sys = { version = "0.35.0", features = ["bundled"] } wait-timeout = "0.2.1" +[target.'cfg(unix)'.dependencies] +libc = { workspace = true } + [dev-dependencies] tempfile = { workspace = true } tokio-tungstenite = { workspace = true } diff --git a/server/src/main.rs b/server/src/main.rs index d957c081..a35037c4 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -124,6 +124,19 @@ fn resolve_path_arg(path_str: Option<&str>, cwd: &std::path::Path) -> Option Result<(), std::io::Error> { + // Reap zombie grandchildren on Unix (for native deployments without tini/init). + // Docker containers with `init: true` in docker-compose.yml already have tini + // as PID 1 for this. For native macOS/Linux, poll waitpid(-1, WNOHANG) in a + // background thread so orphaned grandchildren don't accumulate as zombies. + #[cfg(unix)] + std::thread::spawn(|| loop { + // SAFETY: waitpid(-1, ...) with WNOHANG is always safe to call. + unsafe { + while libc::waitpid(-1, std::ptr::null_mut(), libc::WNOHANG) > 0 {} + } + std::thread::sleep(std::time::Duration::from_secs(5)); + }); + let app_state = Arc::new(SessionState::default()); let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")); let store = Arc::new(