mio_timerfd/
lib.rs

1//! # mio-timerfd
2//!
3//! A linux timerfd wrapper for mio, making it fairly simple to integrate
4//! timers into mio-based systems with minimal overhead. Reading timerfd(7)
5//! is recommended for using this library, though for simple use all you
6//! really need to know is:
7//!
8//! ```rust
9//! # use std::time::Duration;
10//! # use mio_timerfd::*;
11//! # use mio::*;
12//! let mut timer = TimerFd::new(ClockId::Monotonic).unwrap();
13//! timer.set_timeout(&Duration::from_millis(10)).unwrap();
14//!
15//! let mut poll = Poll::new().unwrap();
16//! let mut events = Events::with_capacity(64);
17//! poll.registry().register(&mut timer, Token(0), Interest::READABLE).unwrap();
18//!
19//! // will wait for 10ms to pass
20//! poll.poll(&mut events, None).unwrap();
21//! // always call `read` after the timerfd wakes your thread up, or
22//! // else the readability of the fd isn't going to change and therefore
23//! // the next call to poll will either wake immediately if level triggered,
24//! // or never wake for the timerfd again if edge triggered.
25//! let number_of_timeouts = timer.read().unwrap();
26//! # assert!(number_of_timeouts == 1);
27//! ```
28//!
29//! Note that any given timer can only ever contain one of:
30//! * a recurring interval at which to tick. When an interval timeout is set
31//! up the first tick will happen one interval's duration after the time at
32//! which the timer's timeout was set. (IE the time to first tick is the same
33//! as the time between each tick.)
34//! * a single timeout which will occur a given duration after the timeout
35//! was set.
36use libc::{c_int, c_void};
37use mio::event::Source;
38use mio::unix::SourceFd;
39use mio::{Interest, Registry, Token};
40use std::io;
41use std::mem::MaybeUninit;
42use std::os::unix::io::{AsRawFd, RawFd};
43use std::time::Duration;
44
45#[cfg(not(target_os = "linux"))]
46compile_error!("timerfd is a linux specific feature");
47
48//
49//
50// TimerFd
51//
52//
53
54/// A timerfd which can be used to create mio-compatible
55/// timers on linux targets.
56pub struct TimerFd {
57    fd: c_int,
58}
59
60impl TimerFd {
61    /// Create a new timerfd using the given clock; if you're not sure
62    /// what clock to use read timerfd(7) for more details, or know
63    /// that `ClockId::Monotonic` is a good default for most programs.
64    pub fn new(clockid: ClockId) -> io::Result<Self> {
65        let flags = libc::TFD_NONBLOCK | libc::TFD_CLOEXEC;
66        Self::create(clockid.into(), flags)
67    }
68
69    /// Set a single timeout to occur after the specified duration.
70    pub fn set_timeout(&mut self, timeout: &Duration) -> io::Result<()> {
71        // this is overflow safe unless the timeout is > sizeof(long) seconds,
72        // which is a healthy ~68 years for 32 bit or ~2 billion years for 64 bit.
73        let new_value = libc::itimerspec {
74            it_interval: libc::timespec {
75                tv_sec: 0,
76                tv_nsec: 0,
77            },
78            it_value: libc::timespec {
79                tv_sec: timeout.as_secs() as libc::time_t,
80                tv_nsec: timeout.subsec_nanos() as libc::c_long,
81            },
82        };
83        self.settime(0, &new_value).map(|_old_value| ())
84    }
85
86    /// Set a timeout to occur at each interval of the
87    /// specified duration from this point in time forward.
88    pub fn set_timeout_interval(&mut self, timeout: &Duration) -> io::Result<()> {
89        // this is overflow safe unless the timoeout is > ~292 billion years.
90        let new_value = libc::itimerspec {
91            it_interval: libc::timespec {
92                tv_sec: timeout.as_secs() as libc::time_t,
93                tv_nsec: timeout.subsec_nanos() as libc::c_long,
94            },
95            it_value: libc::timespec {
96                tv_sec: timeout.as_secs() as libc::time_t,
97                tv_nsec: timeout.subsec_nanos() as libc::c_long,
98            },
99        };
100        self.settime(0, &new_value).map(|_old_value| ())
101    }
102
103    /// Unset any existing timeouts on the timer,
104    /// making this timerfd inert until rearmed.
105    pub fn disarm(&mut self) -> io::Result<()> {
106        self.set_timeout(&Duration::from_secs(0))
107    }
108
109    /// Read the timerfd to reset the readability of the timerfd,
110    /// and allow determining how many times the timer has elapsed
111    /// since the last read. This should usually be read after
112    /// any wakeups caused by this timerfd, as reading the timerfd
113    /// is important to reset the readability of the timerfd.
114    ///
115    /// Failing to call this after this timerfd causes a wakeup
116    /// will result in immediately re-waking on this timerfd if
117    /// level polling, or never re-waking if edge polling.
118    pub fn read(&self) -> io::Result<u64> {
119        let mut buf = [0u8; 8];
120        let ret = unsafe { libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, buf.len()) };
121        if ret == 8 {
122            Ok(u64::from_ne_bytes(buf))
123        } else if ret == -1 {
124            let errno = unsafe { *libc::__errno_location() };
125            if errno == libc::EAGAIN {
126                Ok(0)
127            } else {
128                Err(io::Error::from_raw_os_error(errno))
129            }
130        } else {
131            panic!("reading a timerfd should never yield {} bytes", ret);
132        }
133    }
134
135    /// Wrapper of `timerfd_create` from timerfd_create(7); For
136    /// most users it's probably easier to use the `TimerFd::new`.
137    ///
138    /// Note that this library may cause the thread to block when
139    /// `TimerFd::read` is called if the `TFD_NONBLOCK` flag is
140    /// not included in the flags.
141    pub fn create(clockid: c_int, flags: c_int) -> io::Result<Self> {
142        let fd = unsafe { libc::timerfd_create(clockid, flags) };
143        if fd == -1 {
144            Err(io::Error::last_os_error())
145        } else {
146            Ok(Self { fd })
147        }
148    }
149
150    /// Wrapper of `timerfd_settime` from timerfd_create(7); For most
151    /// users it's probably easier to use the `TimerFd::set_timeout` or
152    /// the `TimerFd::set_timeout_interval` functions.
153    pub fn settime(
154        &mut self,
155        flags: c_int,
156        new_value: &libc::itimerspec,
157    ) -> io::Result<libc::itimerspec> {
158        let mut old_spec_mem = MaybeUninit::<libc::itimerspec>::uninit();
159        let ret =
160            unsafe { libc::timerfd_settime(self.fd, flags, new_value, old_spec_mem.as_mut_ptr()) };
161        if ret == -1 {
162            Err(io::Error::last_os_error())
163        } else {
164            let old_spec = unsafe { old_spec_mem.assume_init() };
165            Ok(old_spec)
166        }
167    }
168
169    /// Wrapper of `timerfd_gettime` from timerfd_create(7)
170    pub fn gettime(&self) -> io::Result<libc::itimerspec> {
171        let mut old_spec_mem = MaybeUninit::<libc::itimerspec>::uninit();
172        let ret = unsafe { libc::timerfd_gettime(self.fd, old_spec_mem.as_mut_ptr()) };
173        if ret == -1 {
174            Err(io::Error::last_os_error())
175        } else {
176            let old_spec = unsafe { old_spec_mem.assume_init() };
177            Ok(old_spec)
178        }
179    }
180}
181
182impl AsRawFd for TimerFd {
183    fn as_raw_fd(&self) -> RawFd {
184        self.fd
185    }
186}
187
188impl Source for TimerFd {
189    fn register(
190        &mut self,
191        registry: &Registry,
192        token: Token,
193        interest: Interest,
194    ) -> io::Result<()> {
195        SourceFd(&self.fd).register(registry, token, interest)
196    }
197
198    fn reregister(
199        &mut self,
200        registry: &Registry,
201        token: Token,
202        interest: Interest,
203    ) -> io::Result<()> {
204        SourceFd(&self.fd).reregister(registry, token, interest)
205    }
206
207    fn deregister(&mut self, registry: &Registry) -> io::Result<()> {
208        SourceFd(&self.fd).deregister(registry)
209    }
210}
211
212impl Drop for TimerFd {
213    fn drop(&mut self) {
214        let _ = unsafe { libc::close(self.fd) };
215    }
216}
217
218//
219//
220// ClockId
221//
222//
223
224/// Clock used to mark the progress of the timer. timerfd_create(7)
225#[derive(Copy, Clone)]
226pub enum ClockId {
227    RealTime,
228    Monotonic,
229    BootTime,
230    RealTimeAlarm,
231    BootTimeAlarm,
232}
233
234impl Into<c_int> for ClockId {
235    fn into(self) -> c_int {
236        match self {
237            ClockId::RealTime => libc::CLOCK_REALTIME,
238            ClockId::Monotonic => libc::CLOCK_MONOTONIC,
239            ClockId::BootTime => libc::CLOCK_BOOTTIME,
240            ClockId::RealTimeAlarm => libc::CLOCK_REALTIME_ALARM,
241            ClockId::BootTimeAlarm => libc::CLOCK_BOOTTIME_ALARM,
242        }
243    }
244}
245
246//
247//
248// Testing
249//
250//
251
252#[cfg(test)]
253mod test {
254    use super::*;
255    use mio::{Events, Poll};
256
257    const TOK: Token = Token(0);
258    const TIMEOUT: Duration = Duration::from_millis(60);
259
260    #[test]
261    fn single_timeout() {
262        let mut poll = Poll::new().unwrap();
263        let mut events = Events::with_capacity(1024);
264        let mut timer = TimerFd::new(ClockId::Monotonic).unwrap();
265        timer.set_timeout(&TIMEOUT).unwrap();
266        poll.registry()
267            .register(&mut timer, TOK, Interest::READABLE)
268            .unwrap();
269
270        // timer should not elapse before the timeout
271        poll.poll(&mut events, Some(TIMEOUT / 2)).unwrap();
272        assert!(events.is_empty());
273        assert!(timer.read().unwrap() == 0);
274
275        // timer should elapse after its timeout has passed
276        poll.poll(&mut events, Some(TIMEOUT)).unwrap();
277        assert!(!events.is_empty());
278        assert!(timer.read().unwrap() == 1);
279
280        // timer should not elapse again without a rearm
281        poll.poll(&mut events, Some(TIMEOUT)).unwrap();
282        assert!(events.is_empty());
283        assert!(timer.read().unwrap() == 0);
284    }
285
286    #[test]
287    fn disarm_rearm_single_timeout() {
288        let mut poll = Poll::new().unwrap();
289        let mut events = Events::with_capacity(1024);
290        let mut timer = TimerFd::new(ClockId::Monotonic).unwrap();
291        timer.set_timeout(&TIMEOUT).unwrap();
292        poll.registry()
293            .register(&mut timer, TOK, Interest::READABLE)
294            .unwrap();
295
296        // timer should not elapse before the timeout
297        poll.poll(&mut events, Some(TIMEOUT / 2)).unwrap();
298        assert!(events.is_empty());
299        assert!(timer.read().unwrap() == 0);
300
301        // timer should not elapse after its first
302        // timeout has passed if we disarm the timer.
303        timer.disarm().unwrap();
304        poll.poll(&mut events, Some(TIMEOUT)).unwrap();
305        assert!(events.is_empty());
306        assert!(timer.read().unwrap() == 0);
307
308        // timer should elapse after the rearmed timeout
309        timer.set_timeout(&TIMEOUT).unwrap();
310        poll.poll(&mut events, Some(TIMEOUT * 2)).unwrap();
311        assert!(!events.is_empty());
312        assert!(timer.read().unwrap() == 1);
313    }
314
315    #[test]
316    fn timeout_interval() {
317        let mut poll = Poll::new().unwrap();
318        let mut events = Events::with_capacity(1024);
319        let mut timer = TimerFd::new(ClockId::Monotonic).unwrap();
320        timer.set_timeout_interval(&TIMEOUT).unwrap();
321        poll.registry()
322            .register(&mut timer, TOK, Interest::READABLE)
323            .unwrap();
324
325        // timer should not elapse before the timeout
326        poll.poll(&mut events, Some(TIMEOUT / 2)).unwrap();
327        assert!(events.is_empty());
328        assert!(timer.read().unwrap() == 0);
329
330        // timer should elapsed after its timeout
331        poll.poll(&mut events, Some(TIMEOUT)).unwrap();
332        assert!(!events.is_empty());
333        assert!(timer.read().unwrap() == 1);
334
335        // timer should elapse again after another timeout
336        poll.poll(&mut events, Some(TIMEOUT * 2)).unwrap();
337        assert!(!events.is_empty());
338        assert!(timer.read().unwrap() == 1);
339    }
340
341    #[test]
342    fn disarm_rearm_timeout_interval() {
343        let mut poll = Poll::new().unwrap();
344        let mut events = Events::with_capacity(1024);
345        let mut timer = TimerFd::new(ClockId::Monotonic).unwrap();
346        timer.set_timeout_interval(&TIMEOUT).unwrap();
347        poll.registry()
348            .register(&mut timer, TOK, Interest::READABLE)
349            .unwrap();
350
351        // timer should not elapse before the timeout
352        poll.poll(&mut events, Some(TIMEOUT / 2)).unwrap();
353        assert!(events.is_empty());
354        assert!(timer.read().unwrap() == 0);
355
356        // timer should not elapse after its first
357        // timeout has passed if we disarm the timer,
358        timer.disarm().unwrap();
359        poll.poll(&mut events, Some(TIMEOUT)).unwrap();
360        assert!(events.is_empty());
361        assert!(timer.read().unwrap() == 0);
362
363        // timer should elapse after the rearmed timeout
364        timer.set_timeout_interval(&TIMEOUT).unwrap();
365        poll.poll(&mut events, Some(TIMEOUT + (TIMEOUT / 2)))
366            .unwrap();
367        assert!(!events.is_empty());
368        assert!(timer.read().unwrap() == 1);
369
370        // timer should elapse after the rearmed timeout
371        timer.set_timeout_interval(&TIMEOUT).unwrap();
372        poll.poll(&mut events, Some(TIMEOUT + (TIMEOUT / 2)))
373            .unwrap();
374        assert!(!events.is_empty());
375        assert!(timer.read().unwrap() == 1);
376    }
377
378    #[test]
379    fn deregister_and_drop() {
380        let mut poll = Poll::new().unwrap();
381        let mut events = Events::with_capacity(1024);
382
383        let mut timer_one = TimerFd::new(ClockId::Monotonic).unwrap();
384        timer_one.set_timeout(&Duration::from_millis(32)).unwrap();
385        poll.registry()
386            .register(&mut timer_one, Token(1), Interest::READABLE)
387            .unwrap();
388        let mut timer_two = TimerFd::new(ClockId::Monotonic).unwrap();
389        timer_two.set_timeout(&Duration::from_millis(64)).unwrap();
390        poll.registry()
391            .register(&mut timer_two, Token(2), Interest::READABLE)
392            .unwrap();
393
394        // ensure we can deregister and drop a previously
395        // registered timer without any issue.
396        poll.poll(&mut events, Some(Duration::from_millis(5)))
397            .unwrap();
398        assert!(events.is_empty());
399        poll.registry().deregister(&mut timer_one).unwrap();
400        std::mem::drop(timer_one);
401
402        poll.poll(&mut events, Some(Duration::from_millis(500)))
403            .unwrap();
404        assert!(!events.is_empty());
405        for event in events.iter() {
406            match event.token() {
407                Token(1) => panic!(),
408                Token(2) => {}
409                _ => panic!(),
410            }
411        }
412    }
413
414    #[test]
415    fn multiple_timers() {
416        use std::time::Instant;
417
418        let deadline = Instant::now() + Duration::from_millis(330);
419        let mut count_one = 0;
420        let mut count_two = 0;
421        let mut count_three = 0;
422        let mut count_four = 0;
423
424        let mut poll = Poll::new().unwrap();
425        let mut events = Events::with_capacity(1024);
426
427        // timer one should tick once at 10ms
428        let mut timer_one = TimerFd::new(ClockId::Monotonic).unwrap();
429        timer_one.set_timeout(&Duration::from_millis(100)).unwrap();
430        poll.registry()
431            .register(&mut timer_one, Token(1), Interest::READABLE)
432            .unwrap();
433
434        // timer two should tick each 10ms
435        let mut timer_two = TimerFd::new(ClockId::Monotonic).unwrap();
436        timer_two
437            .set_timeout_interval(&Duration::from_millis(100))
438            .unwrap();
439        poll.registry()
440            .register(&mut timer_two, Token(2), Interest::READABLE)
441            .unwrap();
442
443        // timer three should tick once at 20ms
444        let mut timer_three = TimerFd::new(ClockId::Monotonic).unwrap();
445        timer_three
446            .set_timeout(&Duration::from_millis(200))
447            .unwrap();
448        poll.registry()
449            .register(&mut timer_three, Token(3), Interest::READABLE)
450            .unwrap();
451
452        // timer four should tick each 30ms
453        let mut timer_four = TimerFd::new(ClockId::Monotonic).unwrap();
454        timer_four
455            .set_timeout_interval(&Duration::from_millis(300))
456            .unwrap();
457        poll.registry()
458            .register(&mut timer_four, Token(4), Interest::READABLE)
459            .unwrap();
460
461        loop {
462            poll.poll(&mut events, Some(deadline - Instant::now()))
463                .unwrap();
464            if events.is_empty() {
465                break;
466            }
467            for event in events.iter() {
468                match event.token() {
469                    Token(1) => {
470                        let _ = timer_one.read();
471                        count_one += 1;
472                        if count_one == 1 {
473                            assert!(count_two <= 1);
474                            assert!(count_three == 0);
475                            assert!(count_four == 0);
476                            timer_one.set_timeout(&Duration::from_millis(150)).unwrap();
477                        }
478                    }
479                    Token(2) => {
480                        let _ = timer_two.read();
481                        count_two += 1;
482                        assert!(count_two == 1 || count_two == 2);
483                        // only let this timer tick twice
484                        if count_two >= 2 {
485                            timer_two.disarm().unwrap();
486                        }
487                        // check ticks on other clocks make sense
488                        if count_two == 1 {
489                            assert!(count_one <= 1);
490                            assert!(count_three == 0);
491                            assert!(count_four == 0);
492                        } else if count_two == 2 {
493                            assert!(count_one == 1);
494                            assert!(count_three <= 1);
495                            assert!(count_four == 0);
496                        }
497                    }
498                    Token(3) => {
499                        let _ = timer_three.read();
500                        count_three += 1;
501                        assert!(count_one == 1);
502                        assert!(count_two == 1 || count_two == 2);
503                        assert!(count_three == 1);
504                        assert!(count_four == 0);
505                    }
506                    Token(4) => {
507                        let _ = timer_four.read();
508                        count_four += 1;
509                        assert!(count_one == 2);
510                        assert!(count_two == 2);
511                        assert!(count_three == 1);
512                        assert!(count_four == 1);
513                    }
514                    _ => unreachable!(),
515                }
516            }
517        }
518
519        assert!(count_one == 2);
520        assert!(count_two == 2);
521        assert!(count_three == 1);
522        assert!(count_four == 1);
523    }
524}