use std::cell::RefCell;
use std::io;
use std::os::raw::c_int;
use std::os::unix::io::AsRawFd;
use std::rc::Rc;
use mio::{Evented, Poll, PollOpt, Ready, Token};
use nix::sys::signal::SigSet;
pub use nix::sys::signal::Signal;
pub use nix::sys::signalfd::siginfo;
use nix::sys::signalfd::{SfdFlags, SignalFd};
use {EventDispatcher, EventSource};
#[derive(Copy, Clone)]
pub struct Event {
info: siginfo,
}
impl Event {
pub fn signal(&self) -> Signal {
Signal::from_c_int(self.info.ssi_signo as c_int).unwrap()
}
pub fn full_info(&self) -> siginfo {
self.info
}
}
pub struct Signals {
sfd: Rc<RefCell<SignalFd>>,
mask: SigSet,
}
impl Signals {
pub fn new(signals: &[Signal]) -> io::Result<Signals> {
let mut mask = SigSet::empty();
for &s in signals {
mask.add(s);
}
mask.thread_block().map_err(no_nix_err)?;
let sfd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK | SfdFlags::SFD_CLOEXEC)
.map_err(no_nix_err)?;
Ok(Signals {
sfd: Rc::new(RefCell::new(sfd)),
mask,
})
}
pub fn add_signals(&mut self, signals: &[Signal]) -> io::Result<()> {
for &s in signals {
self.mask.add(s);
}
self.mask.thread_block().map_err(no_nix_err)?;
self.sfd
.borrow_mut()
.set_mask(&self.mask)
.map_err(no_nix_err)?;
Ok(())
}
pub fn remove_signals(&mut self, signals: &[Signal]) -> io::Result<()> {
let mut removed = SigSet::empty();
for &s in signals {
self.mask.remove(s);
removed.add(s);
}
removed.thread_unblock().map_err(no_nix_err)?;
self.sfd
.borrow_mut()
.set_mask(&self.mask)
.map_err(no_nix_err)?;
Ok(())
}
pub fn set_signals(&mut self, signals: &[Signal]) -> io::Result<()> {
let mut new_mask = SigSet::empty();
for &s in signals {
new_mask.add(s);
}
self.mask.thread_unblock().map_err(no_nix_err)?;
new_mask.thread_block().map_err(no_nix_err)?;
self.sfd
.borrow_mut()
.set_mask(&new_mask)
.map_err(no_nix_err)?;
self.mask = new_mask;
Ok(())
}
}
impl Drop for Signals {
fn drop(&mut self) {
if let Err(e) = self.mask.thread_unblock() {
eprintln!("[calloop] Failed to unmask signals: {:?}", e);
}
}
}
fn no_nix_err(err: ::nix::Error) -> io::Error {
match err {
::nix::Error::Sys(errno) => errno.into(),
_ => unreachable!(),
}
}
impl Evented for Signals {
fn register(
&self,
poll: &Poll,
token: Token,
interest: Ready,
opts: PollOpt,
) -> io::Result<()> {
::mio::unix::EventedFd(&self.sfd.borrow().as_raw_fd()).register(poll, token, interest, opts)
}
fn reregister(
&self,
poll: &Poll,
token: Token,
interest: Ready,
opts: PollOpt,
) -> io::Result<()> {
::mio::unix::EventedFd(&self.sfd.borrow().as_raw_fd())
.reregister(poll, token, interest, opts)
}
fn deregister(&self, poll: &Poll) -> io::Result<()> {
::mio::unix::EventedFd(&self.sfd.borrow().as_raw_fd()).deregister(poll)
}
}
impl EventSource for Signals {
type Event = Event;
fn interest(&self) -> Ready {
Ready::readable()
}
fn pollopts(&self) -> PollOpt {
PollOpt::edge()
}
fn make_dispatcher<Data: 'static, F: FnMut(Event, &mut Data) + 'static>(
&self,
callback: F,
) -> Rc<RefCell<EventDispatcher<Data>>> {
Rc::new(RefCell::new(Dispatcher {
_data: ::std::marker::PhantomData,
callback,
sfd: self.sfd.clone(),
}))
}
}
struct Dispatcher<Data, F: FnMut(Event, &mut Data) + 'static> {
_data: ::std::marker::PhantomData<fn(&mut Data)>,
callback: F,
sfd: Rc<RefCell<SignalFd>>,
}
impl<Data, F: FnMut(Event, &mut Data) + 'static> EventDispatcher<Data> for Dispatcher<Data, F> {
fn ready(&mut self, _: Ready, data: &mut Data) {
loop {
let ret = self.sfd.borrow_mut().read_signal();
match ret {
Ok(Some(info)) => (self.callback)(Event { info }, data),
Ok(None) => {
break;
}
Err(e) => {
eprintln!("[calloop] Error reading from signalfd: {:?}", e);
break;
}
}
}
}
}