use std::{collections::HashSet, process};
use log::{debug, info};
use nix::sys::signal::{kill, Signal};
use prefork::{Pid, Prefork, Result};
use signal_hook::{
consts::{SIGCHLD, SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGUSR2},
iterator::Signals,
};
fn child(child_num: u32, _: ()) {
info!("Starting child {child_num}");
let mut signals = Signals::new([SIGUSR1, SIGUSR2]).expect("catch signals");
for signal in signals.forever() {
info!("Child {child_num} got signal {signal}");
}
info!("Stopping child {child_num}");
}
fn manage_children(mut pids: HashSet<Pid>) -> Result<()> {
let parent_pid = process::id();
debug!("Handling signals in parent {parent_pid}");
let mut signals = Signals::new([SIGINT, SIGTERM, SIGQUIT, SIGUSR1, SIGUSR2, SIGCHLD])?;
for signal in signals.forever() {
match signal {
SIGCHLD => {
prefork::wait_process(&mut pids);
if pids.is_empty() {
break;
}
}
SIGUSR1 | SIGUSR2 => {
let signal = Signal::try_from(signal).expect("convert i32 signal for kill");
for child in &pids {
kill(child.clone(), signal).expect("forward signal to child");
}
}
_ => break,
}
}
prefork::kill_all(pids)
}
fn main() {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.without_time()
.init();
let mut server = Prefork::from_resource(())
.with_num_processes(10)
.with_init(child)
.server();
let Some(pids) = server.prefork().expect("fork") else {
return;
};
manage_children(pids).expect("well behaved children");
}