use std::convert::TryFrom;
use std::os::raw::c_int;
use nix::sys::signal::SigSet;
pub use nix::sys::signal::Signal;
pub use nix::sys::signalfd::siginfo;
use nix::sys::signalfd::{SfdFlags, SignalFd};
use super::generic::Generic;
use crate::{EventSource, Interest, Mode, Poll, PostAction, Readiness, Token, TokenFactory};
#[derive(Copy, Clone, Debug)]
pub struct Event {
info: siginfo,
}
impl Event {
pub fn signal(&self) -> Signal {
Signal::try_from(self.info.ssi_signo as c_int).unwrap()
}
pub fn full_info(&self) -> siginfo {
self.info
}
}
#[derive(Debug)]
pub struct Signals {
sfd: Generic<SignalFd>,
mask: SigSet,
}
impl Signals {
pub fn new(signals: &[Signal]) -> crate::Result<Signals> {
let mut mask = SigSet::empty();
for &s in signals {
mask.add(s);
}
mask.thread_block()?;
let sfd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK | SfdFlags::SFD_CLOEXEC)?;
Ok(Signals {
sfd: Generic::new(sfd, Interest::READ, Mode::Level),
mask,
})
}
pub fn add_signals(&mut self, signals: &[Signal]) -> crate::Result<()> {
for &s in signals {
self.mask.add(s);
}
self.mask.thread_block()?;
self.sfd.file.set_mask(&self.mask)?;
Ok(())
}
pub fn remove_signals(&mut self, signals: &[Signal]) -> crate::Result<()> {
let mut removed = SigSet::empty();
for &s in signals {
self.mask.remove(s);
removed.add(s);
}
removed.thread_unblock()?;
self.sfd.file.set_mask(&self.mask)?;
Ok(())
}
pub fn set_signals(&mut self, signals: &[Signal]) -> crate::Result<()> {
let mut new_mask = SigSet::empty();
for &s in signals {
new_mask.add(s);
}
self.mask.thread_unblock()?;
new_mask.thread_block()?;
self.sfd.file.set_mask(&new_mask)?;
self.mask = new_mask;
Ok(())
}
}
impl Drop for Signals {
fn drop(&mut self) {
if let Err(e) = self.mask.thread_unblock() {
log::warn!("[calloop] Failed to unmask signals: {:?}", e);
}
}
}
impl EventSource for Signals {
type Event = Event;
type Metadata = ();
type Ret = ();
type Error = SignalError;
fn process_events<C>(
&mut self,
readiness: Readiness,
token: Token,
mut callback: C,
) -> Result<PostAction, Self::Error>
where
C: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret,
{
self.sfd
.process_events(readiness, token, |_, sfd| {
loop {
match sfd.read_signal() {
Ok(Some(info)) => callback(Event { info }, &mut ()),
Ok(None) => break,
Err(e) => {
log::warn!("[callop] Error reading from signalfd: {}", e);
return Err(e.into());
}
}
}
Ok(PostAction::Continue)
})
.map_err(|e| SignalError(e.into()))
}
fn register(&mut self, poll: &mut Poll, token_factory: &mut TokenFactory) -> crate::Result<()> {
self.sfd.register(poll, token_factory)
}
fn reregister(
&mut self,
poll: &mut Poll,
token_factory: &mut TokenFactory,
) -> crate::Result<()> {
self.sfd.reregister(poll, token_factory)
}
fn unregister(&mut self, poll: &mut Poll) -> crate::Result<()> {
self.sfd.unregister(poll)
}
}
#[derive(thiserror::Error, Debug)]
#[error(transparent)]
pub struct SignalError(Box<dyn std::error::Error + Sync + Send>);