1
0
Fork 0
forked from wry/wry
wry/src/sighand.rs
2022-02-05 18:14:24 +01:00

74 lines
2.3 KiB
Rust

use crate::event_loop::{EventLoop, EventLoopDispatcher, EventLoopId};
use crate::EventLoopError;
use std::error::Error;
use std::rc::Rc;
use thiserror::Error;
use uapi::{c, Errno, OwnedFd};
#[derive(Debug, Error)]
pub enum SighandError {
#[error("The signal fd is in an error state")]
ErrorEvent,
#[error("Could not read from the signal fd")]
ReadFailed(#[source] std::io::Error),
#[error("Could not block the signalfd signals")]
BlockFailed(#[source] std::io::Error),
#[error("Could not create a signalfd")]
CreateFailed(#[source] std::io::Error),
#[error("The event loop caused an error")]
EventLoopError(#[from] EventLoopError),
}
pub fn install(el: &Rc<EventLoop>) -> Result<(), SighandError> {
let mut set: c::sigset_t = uapi::pod_zeroed();
uapi::sigaddset(&mut set, c::SIGINT).unwrap();
uapi::sigaddset(&mut set, c::SIGTERM).unwrap();
if let Err(e) = uapi::pthread_sigmask(c::SIG_BLOCK, Some(&set), None) {
return Err(SighandError::BlockFailed(e.into()));
}
let fd = match uapi::signalfd_new(&set, c::SFD_CLOEXEC | c::SFD_NONBLOCK) {
Ok(fd) => fd,
Err(e) => return Err(SighandError::CreateFailed(e.into())),
};
let id = el.id();
let sh = Rc::new(Sighand {
fd,
id,
el: el.clone(),
});
el.insert(id, Some(sh.fd.raw()), c::EPOLLIN, sh)?;
Ok(())
}
struct Sighand {
fd: OwnedFd,
id: EventLoopId,
el: Rc<EventLoop>,
}
impl EventLoopDispatcher for Sighand {
fn dispatch(self: Rc<Self>, events: i32) -> Result<(), Box<dyn Error>> {
if events & (c::EPOLLERR | c::EPOLLHUP) != 0 {
return Err(Box::new(SighandError::ErrorEvent));
}
let mut sigfd: c::signalfd_siginfo = uapi::pod_zeroed();
loop {
if let Err(e) = uapi::read(self.fd.raw(), &mut sigfd) {
match e {
Errno(c::EAGAIN) => break,
_ => return Err(Box::new(SighandError::ReadFailed(e.into()))),
}
}
log::info!("Received signal {}", sigfd.ssi_signo);
log::info!("Exiting");
self.el.stop();
}
Ok(())
}
}
impl Drop for Sighand {
fn drop(&mut self) {
let _ = self.el.remove(self.id);
}
}