use crate::coord::Coordinator;
use crate::error::{Error, Result};
use crate::reason::ShutdownReason;
use crate::signal::{Signal, SignalSet};
use crate::token::ShutdownTrigger;
pub(crate) fn install(coord: &Coordinator) -> Result<()> {
let trigger = coord.trigger();
let set = coord.signals();
install_inner(set, trigger)
}
#[cfg(unix)]
fn install_inner(set: SignalSet, trigger: ShutdownTrigger) -> Result<()> {
use tokio::signal::unix::{signal, SignalKind};
fn reg(sig: Signal, kind: SignalKind, set: SignalSet, trigger: &ShutdownTrigger) -> Result<()> {
if !set.contains(sig) {
return Ok(());
}
let mut stream = signal(kind).map_err(|e| Error::SignalRegistration {
signal: sig,
source: e,
})?;
let t = trigger.clone();
tokio::spawn(async move {
while stream.recv().await.is_some() {
let _ = t.trigger(ShutdownReason::Signal(sig));
}
});
Ok(())
}
reg(Signal::Terminate, SignalKind::terminate(), set, &trigger)?;
reg(Signal::Interrupt, SignalKind::interrupt(), set, &trigger)?;
reg(Signal::Quit, SignalKind::quit(), set, &trigger)?;
reg(Signal::Hangup, SignalKind::hangup(), set, &trigger)?;
reg(Signal::Pipe, SignalKind::pipe(), set, &trigger)?;
reg(Signal::User1, SignalKind::user_defined1(), set, &trigger)?;
reg(Signal::User2, SignalKind::user_defined2(), set, &trigger)?;
Ok(())
}
#[cfg(windows)]
fn install_inner(set: SignalSet, trigger: ShutdownTrigger) -> Result<()> {
use tokio::signal::windows::{ctrl_break, ctrl_c, ctrl_close, ctrl_shutdown};
macro_rules! spawn_listener {
($sig:expr, $factory:expr) => {{
if set.contains($sig) {
let mut s = $factory().map_err(|e| Error::SignalRegistration {
signal: $sig,
source: e,
})?;
let t = trigger.clone();
tokio::spawn(async move {
while s.recv().await.is_some() {
let _ = t.trigger(ShutdownReason::Signal($sig));
}
});
}
}};
}
spawn_listener!(Signal::Interrupt, ctrl_c);
spawn_listener!(Signal::Quit, ctrl_break);
spawn_listener!(Signal::Terminate, ctrl_close);
spawn_listener!(Signal::Hangup, ctrl_shutdown);
let _ = trigger;
Ok(())
}
#[cfg(not(any(unix, windows)))]
fn install_inner(_set: SignalSet, _trigger: ShutdownTrigger) -> Result<()> {
Ok(())
}