1 // Copyright 2020 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::time::Duration;
6 
7 use sys_util::{Result as SysResult, TimerFd};
8 
9 use crate::{AsyncResult, Executor, IntoAsync, IoSourceExt};
10 #[cfg(test)]
11 use crate::{FdExecutor, URingExecutor};
12 
13 /// An async version of sys_util::TimerFd.
14 pub struct TimerAsync {
15     io_source: Box<dyn IoSourceExt<TimerFd>>,
16 }
17 
18 impl TimerAsync {
new(timer: TimerFd, ex: &Executor) -> AsyncResult<TimerAsync>19     pub fn new(timer: TimerFd, ex: &Executor) -> AsyncResult<TimerAsync> {
20         ex.async_from(timer)
21             .map(|io_source| TimerAsync { io_source })
22     }
23 
24     #[cfg(test)]
new_poll(timer: TimerFd, ex: &FdExecutor) -> AsyncResult<TimerAsync>25     pub(crate) fn new_poll(timer: TimerFd, ex: &FdExecutor) -> AsyncResult<TimerAsync> {
26         crate::executor::async_poll_from(timer, ex).map(|io_source| TimerAsync { io_source })
27     }
28 
29     #[cfg(test)]
new_uring(timer: TimerFd, ex: &URingExecutor) -> AsyncResult<TimerAsync>30     pub(crate) fn new_uring(timer: TimerFd, ex: &URingExecutor) -> AsyncResult<TimerAsync> {
31         crate::executor::async_uring_from(timer, ex).map(|io_source| TimerAsync { io_source })
32     }
33 
34     /// Gets the next value from the timer.
next_val(&self) -> AsyncResult<u64>35     pub async fn next_val(&self) -> AsyncResult<u64> {
36         self.io_source.read_u64().await
37     }
38 
39     /// Sets the timer to expire after `dur`.  If `interval` is not `None` it represents
40     /// the period for repeated expirations after the initial expiration.  Otherwise
41     /// the timer will expire just once.  Cancels any existing duration and repeating interval.
reset(&mut self, dur: Duration, interval: Option<Duration>) -> SysResult<()>42     pub fn reset(&mut self, dur: Duration, interval: Option<Duration>) -> SysResult<()> {
43         self.io_source.as_source_mut().reset(dur, interval)
44     }
45 }
46 
47 impl IntoAsync for TimerFd {}
48 
49 #[cfg(test)]
50 mod tests {
51     use super::*;
52     use std::time::{Duration, Instant};
53 
54     #[test]
one_shot()55     fn one_shot() {
56         async fn this_test(ex: &URingExecutor) -> () {
57             let tfd = TimerFd::new().expect("failed to create timerfd");
58             assert_eq!(tfd.is_armed().unwrap(), false);
59 
60             let dur = Duration::from_millis(200);
61             let now = Instant::now();
62             tfd.reset(dur, None).expect("failed to arm timer");
63 
64             assert_eq!(tfd.is_armed().unwrap(), true);
65 
66             let t = TimerAsync::new_uring(tfd, ex).unwrap();
67             let count = t.next_val().await.expect("unable to wait for timer");
68 
69             assert_eq!(count, 1);
70             assert!(now.elapsed() >= dur);
71         }
72 
73         let ex = URingExecutor::new().unwrap();
74         ex.run_until(this_test(&ex)).unwrap();
75     }
76 
77     #[test]
one_shot_fd()78     fn one_shot_fd() {
79         async fn this_test(ex: &FdExecutor) -> () {
80             let tfd = TimerFd::new().expect("failed to create timerfd");
81             assert_eq!(tfd.is_armed().unwrap(), false);
82 
83             let dur = Duration::from_millis(200);
84             let now = Instant::now();
85             tfd.reset(dur, None).expect("failed to arm timer");
86 
87             assert_eq!(tfd.is_armed().unwrap(), true);
88 
89             let t = TimerAsync::new_poll(tfd, ex).unwrap();
90             let count = t.next_val().await.expect("unable to wait for timer");
91 
92             assert_eq!(count, 1);
93             assert!(now.elapsed() >= dur);
94         }
95 
96         let ex = FdExecutor::new().unwrap();
97         ex.run_until(this_test(&ex)).unwrap();
98     }
99 }
100