tools: add async signalfd handler

This provides a Stream<Item = siginfo> via nix' signalfd,
by wrapping it in tokio's PollEvented2 struct to allow
polling via tokio's event loop.

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2019-03-11 09:35:47 +01:00
parent d5c34d98c0
commit f54c19989c
2 changed files with 85 additions and 0 deletions

View File

@ -27,6 +27,7 @@ pub mod ticket;
pub mod borrow;
pub mod fs;
pub mod tty;
pub mod signalfd;
#[macro_use]
mod file_logger;

84
src/tools/signalfd.rs Normal file
View File

@ -0,0 +1,84 @@
//! signalfd handling for tokio
use std::os::unix::io::{AsRawFd, RawFd};
use failure::*;
use nix::sys::signalfd::{self, SigSet};
use tokio::prelude::*;
use tokio::reactor::PollEvented2;
type Result<T> = std::result::Result<T, Error>;
pub struct SignalFd {
inner: signalfd::SignalFd,
pinned_fd: Box<RawFd>,
wakeup: PollEvented2<mio::unix::EventedFd<'static>>,
}
impl std::ops::Deref for SignalFd {
type Target = signalfd::SignalFd;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl std::ops::DerefMut for SignalFd {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl SignalFd {
pub fn new(mask: &SigSet) -> Result<Self> {
let inner = signalfd::SignalFd::with_flags(
mask,
signalfd::SfdFlags::SFD_CLOEXEC | signalfd::SfdFlags::SFD_NONBLOCK,
)?;
// box the signalfd's Rawfd, turn it into a raw pointer and create a &'static reference so
// we can store it inthe SignalFd struct...
let pinned_fd = Box::new(inner.as_raw_fd());
let fd_ptr: *const RawFd = &*pinned_fd;
let static_fd: &'static RawFd = unsafe { &*fd_ptr };
let evented = mio::unix::EventedFd(static_fd);
let wakeup = PollEvented2::new(evented);
Ok(Self {
inner,
pinned_fd,
wakeup,
})
}
}
impl Stream for SignalFd {
type Item = signalfd::siginfo;
type Error = Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
let ready = mio::Ready::readable();
match self.wakeup.poll_read_ready(ready) {
Ok(Async::Ready(_)) => (), // go on
Ok(Async::NotReady) => return Ok(Async::NotReady),
Err(e) => return Err(e.into()),
}
match self.inner.read_signal() {
Ok(Some(signal)) => Ok(Async::Ready(Some(signal))),
Ok(None) => {
self.wakeup.clear_read_ready(ready)?;
Ok(Async::NotReady)
}
Err(e) => Err(e.into()),
}
}
}
impl AsRawFd for SignalFd {
fn as_raw_fd(&self) -> RawFd {
*self.pinned_fd
}
}