Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A timerfd based implementation of a timer future for tokio
struct OneShotTimer {
fd: Box<std::os::unix::io::RawFd>,
e: Option<tokio_reactor::PollEvented<mio::unix::EventedFd<'static>>>,
}
impl OneShotTimer {
fn new(d: time::Duration) -> io::Result<Self> {
if d.as_secs() == 0 && d.subsec_nanos() == 0 {
// this would be interpreted as "inactive timer" by timerfd_settime
return Ok(OneShotTimer {
fd: Box::new(0),
e: None,
});
}
let tfd = unsafe { libc::timerfd_create(libc::CLOCK_MONOTONIC, libc::TFD_NONBLOCK) };
if tfd == -1 {
return Err(io::Error::last_os_error());
}
let tfd = Box::new(tfd);
let mtfd = mio::unix::EventedFd(&*tfd);
let e = tokio_reactor::PollEvented::new(mtfd);
let e: tokio_reactor::PollEvented<mio::unix::EventedFd<'static>> =
unsafe { std::mem::transmute(e) };
// arm the timer
let timer = libc::itimerspec {
it_interval: libc::timespec {
tv_sec: 0,
tv_nsec: 0,
},
it_value: libc::timespec {
tv_sec: d.as_secs() as i64,
tv_nsec: d.subsec_nanos() as i64,
},
};
let ret = unsafe { libc::timerfd_settime(*tfd, 0, &timer, std::ptr::null_mut()) };
if ret == -1 {
return Err(io::Error::last_os_error());
}
Ok(OneShotTimer {
fd: tfd,
e: Some(e),
})
}
}
impl Future for OneShotTimer {
type Item = ();
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
if self.e.is_none() {
return Ok(Async::Ready(()));
}
let ready = mio::Ready::readable();
let _ = try_ready!(self.e.as_mut().unwrap().poll_read_ready(ready));
// we don't ever _actually_ need to read from a timerfd
self.e.as_mut().unwrap().clear_read_ready(ready)?;
Ok(Async::Ready(()))
}
}
impl Drop for OneShotTimer {
fn drop(&mut self) {
if let Some(e) = self.e.take() {
drop(e);
unsafe { libc::close(*self.fd) };
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.