use nix::sys::wait::{WaitPidFlag, WaitStatus}; use tokio::signal::unix::{signal, SignalKind, Signal}; use crate::logger::LogWriter; use std::sync::atomic::{AtomicU64, Ordering}; use lazy_static::lazy_static; lazy_static!{ static ref REAP_COUNTER: AtomicU64 = AtomicU64::new(0); } pub struct Reaper { sig_stream: Signal, logger: LogWriter, } impl Reaper { pub fn new(logger: LogWriter) -> Result { let stream = signal(SignalKind::child())?; Ok(Reaper { sig_stream: stream, logger }) } pub async fn reap(&mut self) -> ! { loop { self.sig_stream.recv().await; loop { let wstat = nix::sys::wait::waitpid(nix::unistd::Pid::from_raw(-1), Some(WaitPidFlag::WNOHANG)); match wstat { Ok(ws) => { if LogWriter::is_debug_mode() { let msg = match ws { WaitStatus::Exited(pid, ec) => { Some(format!("{}: WIFEXITED ExitCode={}", pid, ec)) } WaitStatus::Signaled(pid, sig, t) => { Some(format!("{}: WIFSIGNALED Signal={}, IsCoreDump={}", pid, sig, t)) } WaitStatus::Stopped(pid, c) => { Some(format!("{}: WIFSTOPPED Code={}", pid, c)) } WaitStatus::PtraceEvent(pid, sig, c) => { Some(format!("{}: PTRACE_EVENT Signal={}, Value={}", pid, sig, c)) } WaitStatus::PtraceSyscall(pid) => { Some(format!("{}: PTRACE_SYSCALL", pid)) } WaitStatus::Continued(pid) => { Some(format!("{}: WCONTINUED", pid)) } WaitStatus::StillAlive => { None } }; if let Some(v) = msg { REAP_COUNTER.fetch_add(1, Ordering::Relaxed); self.logger.error(format!("reap zombie child {}", v).as_str()).await; } }else{ if ws != WaitStatus::StillAlive { REAP_COUNTER.fetch_add(1, Ordering::Relaxed); } } } Err(_) => {} }; } }; } } pub fn get_count() -> u64 { REAP_COUNTER.load(Ordering::Relaxed) }