signalfd cleanup

- add comment about the boxed file descriptor (and others)
- reexport SigSet and Signal for convenience
- remove Result wrapper (only used once)
- enforce drop order of the PollEvented2 struct with respect
  to the boxed fd

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2019-03-12 09:57:31 +01:00
parent b6b012e3c0
commit 4ba7b6099c

View File

@ -1,18 +1,19 @@
//! signalfd handling for tokio //! signalfd handling for tokio, with some re-exports for convenience
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use failure::*; use failure::*;
use nix::sys::signalfd::{self, SigSet}; use nix::sys::signalfd;
use tokio::prelude::*; use tokio::prelude::*;
use tokio::reactor::PollEvented2; use tokio::reactor::PollEvented2;
type Result<T> = std::result::Result<T, Error>; pub use nix::sys::signal::{SigSet, Signal};
/// Wrapper for `nix::sys::signal::SignalFd` to provide an async `Stream` of `siginfo`.
pub struct SignalFd { pub struct SignalFd {
inner: signalfd::SignalFd, inner: signalfd::SignalFd,
pinned_fd: Box<RawFd>, pinned_fd: Box<RawFd>,
wakeup: PollEvented2<mio::unix::EventedFd<'static>>, wakeup: Option<PollEvented2<mio::unix::EventedFd<'static>>>,
} }
impl std::ops::Deref for SignalFd { impl std::ops::Deref for SignalFd {
@ -30,20 +31,23 @@ impl std::ops::DerefMut for SignalFd {
} }
impl SignalFd { impl SignalFd {
pub fn new(mask: &SigSet) -> Result<Self> { pub fn new(mask: &SigSet) -> Result<Self, Error> {
let inner = signalfd::SignalFd::with_flags( let inner = signalfd::SignalFd::with_flags(
mask, mask,
signalfd::SfdFlags::SFD_CLOEXEC | signalfd::SfdFlags::SFD_NONBLOCK, 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 // EventedFd takes a reference and therefore a lifetime parameter. Since we want to
// we can store it inthe SignalFd struct... // reference something that is part of our own Self, we need to find a work around:
// Pin the file descriptor in memory by boxing it and fake a &'static lifetime.
//
// Note that we must not provide access to this lifetime to the outside!
let pinned_fd = Box::new(inner.as_raw_fd()); let pinned_fd = Box::new(inner.as_raw_fd());
let fd_ptr: *const RawFd = &*pinned_fd; let fd_ptr: *const RawFd = &*pinned_fd;
let static_fd: &'static RawFd = unsafe { &*fd_ptr }; let static_fd: &'static RawFd = unsafe { &*fd_ptr };
let evented = mio::unix::EventedFd(static_fd); let evented = mio::unix::EventedFd(static_fd);
let wakeup = PollEvented2::new(evented); let wakeup = Some(PollEvented2::new(evented));
Ok(Self { Ok(Self {
inner, inner,
@ -60,7 +64,7 @@ impl Stream for SignalFd {
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> { fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
let ready = mio::Ready::readable(); let ready = mio::Ready::readable();
match self.wakeup.poll_read_ready(ready) { match self.wakeup.as_mut().unwrap().poll_read_ready(ready) {
Ok(Async::Ready(_)) => (), // go on Ok(Async::Ready(_)) => (), // go on
Ok(Async::NotReady) => return Ok(Async::NotReady), Ok(Async::NotReady) => return Ok(Async::NotReady),
Err(e) => return Err(e.into()), Err(e) => return Err(e.into()),
@ -69,7 +73,7 @@ impl Stream for SignalFd {
match self.inner.read_signal() { match self.inner.read_signal() {
Ok(Some(signal)) => Ok(Async::Ready(Some(signal))), Ok(Some(signal)) => Ok(Async::Ready(Some(signal))),
Ok(None) => { Ok(None) => {
self.wakeup.clear_read_ready(ready)?; self.wakeup.as_mut().unwrap().clear_read_ready(ready)?;
Ok(Async::NotReady) Ok(Async::NotReady)
} }
Err(e) => Err(e.into()), Err(e) => Err(e.into()),
@ -82,3 +86,9 @@ impl AsRawFd for SignalFd {
*self.pinned_fd *self.pinned_fd
} }
} }
impl Drop for SignalFd {
fn drop(&mut self) {
self.wakeup = None; // enforce drop order
}
}