tokio_timerfd/
lib.rs

1//! This crates provides [tokio-timer](https://docs.rs/tokio-timer)-like API
2//! on top of timerfd. `timerfd` is a Linux-specific API providing timer notifications as
3//! file descriptor read events.
4//!
5//! The advantage of `timerfd` is that it has more granularity than epoll_wait(),
6//! which only provides 1 millisecond timeouts. `timerfd` API allows for nanosecond
7//! precision, but precise timing of the wakeup is not guaranteed on a normal
8//! multitasking system.
9//!
10//! Despite the name, this crate is *not* a part of the tokio project.
11//!
12//! * [`Delay`]: A future that completes at a specified instant in time.
13//! * [`Interval`] A stream that yields at fixed time intervals.
14//! * [`DelayQueue`]: A queue where items are returned once the requested delay
15//!   has expired.
16//!
17//! [`Delay`]: struct.Delay.html
18//! [`DelayQueue`]: struct.DelayQueue.html
19//! [`Interval`]: struct.Interval.html
20
21use std::io::{Error, Result};
22use std::os::unix::io::{AsRawFd, RawFd};
23use std::pin::Pin;
24use std::task::{Context, Poll};
25use std::time::{Duration, Instant};
26
27use futures_core::ready;
28use timerfd::{SetTimeFlags, TimerFd as InnerTimerFd, TimerState};
29use tokio::io::unix::AsyncFd;
30use tokio::io::{AsyncRead, Interest, ReadBuf};
31
32pub use timerfd::ClockId;
33
34mod delay;
35/*
36mod delay_queue;
37*/
38mod interval;
39
40pub use delay::Delay;
41pub use interval::Interval;
42/*
43pub use delay_queue::DelayQueue;
44*/
45
46pub struct TimerFd(AsyncFd<InnerTimerFd>);
47
48impl TimerFd {
49    pub fn new(clock: ClockId) -> std::io::Result<Self> {
50        let fd = InnerTimerFd::new_custom(clock, true, true)?;
51        let inner = AsyncFd::with_interest(fd, Interest::READABLE)?;
52        Ok(TimerFd(inner))
53    }
54
55    fn set_state(&mut self, state: TimerState, flags: SetTimeFlags) {
56        (self.0).get_mut().set_state(state, flags);
57    }
58}
59
60fn read_u64(fd: RawFd) -> Result<u64> {
61    let mut buf = [0u8; 8];
62    let rv = unsafe { libc::read(fd, buf.as_mut_ptr() as *mut _, 8) };
63    match rv {
64        len if len >= 0 => Ok(u64::from_ne_bytes(buf)),
65        _err => Err(Error::last_os_error()),
66    }
67}
68
69impl AsyncRead for TimerFd {
70    fn poll_read(
71        mut self: Pin<&mut Self>,
72        cx: &mut Context<'_>,
73        buf: &mut ReadBuf<'_>,
74    ) -> Poll<Result<()>> {
75        let inner = self.as_mut();
76        let fd = inner.0.as_raw_fd();
77
78        loop {
79            let mut guard = ready!(inner.0.poll_read_ready(cx))?;
80            match guard.try_io(|_| read_u64(fd)) {
81                Ok(res) => {
82                    let num = res?;
83                    buf.put_slice(&num.to_ne_bytes());
84                    break;
85                }
86                Err(_) => continue,
87            }
88        }
89        Poll::Ready(Ok(()))
90    }
91}
92
93/// Create a Future that completes in `duration` from now.
94pub fn sleep(duration: Duration) -> Delay {
95    Delay::new(Instant::now() + duration).expect("can't create delay")
96}