• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 super::{AsyncResult, Error, Executor, IntoAsync, IoSourceExt};
10 
11 #[cfg(test)]
12 use super::{FdExecutor, URingExecutor};
13 
14 /// An async version of sys_util::TimerFd.
15 pub struct TimerAsync {
16     io_source: Box<dyn IoSourceExt<TimerFd>>,
17 }
18 
19 impl TimerAsync {
new(timer: TimerFd, ex: &Executor) -> AsyncResult<TimerAsync>20     pub fn new(timer: TimerFd, ex: &Executor) -> AsyncResult<TimerAsync> {
21         ex.async_from(timer)
22             .map(|io_source| TimerAsync { io_source })
23     }
24 
25     #[cfg(test)]
new_poll(timer: TimerFd, ex: &FdExecutor) -> AsyncResult<TimerAsync>26     pub(crate) fn new_poll(timer: TimerFd, ex: &FdExecutor) -> AsyncResult<TimerAsync> {
27         super::executor::async_poll_from(timer, ex).map(|io_source| TimerAsync { io_source })
28     }
29 
30     #[cfg(test)]
new_uring(timer: TimerFd, ex: &URingExecutor) -> AsyncResult<TimerAsync>31     pub(crate) fn new_uring(timer: TimerFd, ex: &URingExecutor) -> AsyncResult<TimerAsync> {
32         super::executor::async_uring_from(timer, ex).map(|io_source| TimerAsync { io_source })
33     }
34 
35     /// Gets the next value from the timer.
next_val(&self) -> AsyncResult<u64>36     pub async fn next_val(&self) -> AsyncResult<u64> {
37         self.io_source.read_u64().await
38     }
39 
40     /// Async sleep for the given duration
sleep(ex: &Executor, dur: Duration) -> std::result::Result<(), Error>41     pub async fn sleep(ex: &Executor, dur: Duration) -> std::result::Result<(), Error> {
42         let tfd = TimerFd::new().map_err(Error::TimerFd)?;
43         tfd.reset(dur, None).map_err(Error::TimerFd)?;
44         let t = TimerAsync::new(tfd, ex).map_err(Error::TimerAsync)?;
45         t.next_val().await.map_err(Error::TimerAsync)?;
46         Ok(())
47     }
48 
49     /// Sets the timer to expire after `dur`.  If `interval` is not `None` it represents
50     /// the period for repeated expirations after the initial expiration.  Otherwise
51     /// the timer will expire just once.  Cancels any existing duration and repeating interval.
reset(&mut self, dur: Duration, interval: Option<Duration>) -> SysResult<()>52     pub fn reset(&mut self, dur: Duration, interval: Option<Duration>) -> SysResult<()> {
53         self.io_source.as_source_mut().reset(dur, interval)
54     }
55 }
56 
57 impl IntoAsync for TimerFd {}
58 
59 #[cfg(test)]
60 mod tests {
61     use super::{super::uring_executor::use_uring, *};
62     use std::time::{Duration, Instant};
63 
64     #[test]
one_shot()65     fn one_shot() {
66         if !use_uring() {
67             return;
68         }
69 
70         async fn this_test(ex: &URingExecutor) {
71             let tfd = TimerFd::new().expect("failed to create timerfd");
72 
73             let dur = Duration::from_millis(200);
74             let now = Instant::now();
75             tfd.reset(dur, None).expect("failed to arm timer");
76 
77             let t = TimerAsync::new_uring(tfd, ex).unwrap();
78             let count = t.next_val().await.expect("unable to wait for timer");
79 
80             assert_eq!(count, 1);
81             assert!(now.elapsed() >= dur);
82         }
83 
84         let ex = URingExecutor::new().unwrap();
85         ex.run_until(this_test(&ex)).unwrap();
86     }
87 
88     #[test]
one_shot_fd()89     fn one_shot_fd() {
90         async fn this_test(ex: &FdExecutor) {
91             let tfd = TimerFd::new().expect("failed to create timerfd");
92 
93             let dur = Duration::from_millis(200);
94             let now = Instant::now();
95             tfd.reset(dur, None).expect("failed to arm timer");
96 
97             let t = TimerAsync::new_poll(tfd, ex).unwrap();
98             let count = t.next_val().await.expect("unable to wait for timer");
99 
100             assert_eq!(count, 1);
101             assert!(now.elapsed() >= dur);
102         }
103 
104         let ex = FdExecutor::new().unwrap();
105         ex.run_until(this_test(&ex)).unwrap();
106     }
107 
108     #[test]
timer()109     fn timer() {
110         async fn this_test(ex: &Executor) {
111             let dur = Duration::from_millis(200);
112             let now = Instant::now();
113             TimerAsync::sleep(ex, dur).await.expect("unable to sleep");
114             assert!(now.elapsed() >= dur);
115         }
116 
117         let ex = Executor::new().expect("creating an executor failed");
118         ex.run_until(this_test(&ex)).unwrap();
119     }
120 }
121