use crate::{
application::{self, Application},
thread, FrameworkError,
FrameworkErrorKind::{SignalError, ThreadError},
};
use libc::c_int;
use signal_hook::iterator::Signals;
use std::{convert::TryFrom, fmt};
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
#[repr(u32)]
pub enum Signal {
Hup = 1,
Int = 2,
Pipe = 13,
Alrm = 14,
Term = 15,
Chld = 20,
Usr1 = 30,
Usr2 = 31,
}
impl Signal {
pub fn number(self) -> u32 {
self as u32
}
pub fn name(self) -> &'static str {
match self {
Signal::Hup => "SIGHUP",
Signal::Int => "SIGINT",
Signal::Pipe => "SIGPIPE",
Signal::Alrm => "SIGALRM",
Signal::Term => "SIGTERM",
Signal::Chld => "SIGCHLD",
Signal::Usr1 => "SIGUSR1",
Signal::Usr2 => "SIGUSR2",
}
}
}
impl fmt::Display for Signal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name())
}
}
impl TryFrom<u32> for Signal {
type Error = FrameworkError;
fn try_from(num: u32) -> Result<Signal, FrameworkError> {
Ok(match num {
1 => Signal::Hup,
2 => Signal::Int,
13 => Signal::Pipe,
14 => Signal::Alrm,
15 => Signal::Term,
20 => Signal::Chld,
30 => Signal::Usr1,
31 => Signal::Usr2,
other => fail!(SignalError, "unregistered signal number: {}", other),
})
}
}
pub fn register_handler<A, I>(
app_lock: &'static application::Lock<A>,
signals: I,
) -> Result<(), FrameworkError>
where
A: Application + Send + Sync,
I: IntoIterator<Item = Signal>,
{
let mut app = app_lock.write();
let thread_name = thread::Name::new("abscissa::signal");
let signals = Signals::new(signals.into_iter().map(|s| s.number() as c_int))
.map_err(|e| format_err!(ThreadError, "{}", e))?;
app.state_mut()
.threads
.spawn(&thread_name, move || handler_thread(app_lock, signals))
}
fn handler_thread<A>(app_lock: &'static application::Lock<A>, signals: Signals)
where
A: Application,
{
while !thread::should_terminate() {
for sig_num in &signals {
let sig = Signal::try_from(sig_num as u32).unwrap();
debug!("received signal: {}", sig);
let mut app = app_lock.write();
app.handle_signal(sig).unwrap_or_else(|e| {
status_err!("error handling signal: {}", e)
});
}
}
}