xref: /aosp_15_r20/external/crosvm/base/src/timer.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2020 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Instant;
8*bb4ee6a4SAndroid Build Coastguard Worker 
9*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
10*bb4ee6a4SAndroid Build Coastguard Worker 
11*bb4ee6a4SAndroid Build Coastguard Worker use super::Event;
12*bb4ee6a4SAndroid Build Coastguard Worker use super::EventWaitResult;
13*bb4ee6a4SAndroid Build Coastguard Worker use super::FakeClock;
14*bb4ee6a4SAndroid Build Coastguard Worker use super::RawDescriptor;
15*bb4ee6a4SAndroid Build Coastguard Worker use super::Result;
16*bb4ee6a4SAndroid Build Coastguard Worker use crate::descriptor::AsRawDescriptor;
17*bb4ee6a4SAndroid Build Coastguard Worker use crate::descriptor::FromRawDescriptor;
18*bb4ee6a4SAndroid Build Coastguard Worker use crate::descriptor::IntoRawDescriptor;
19*bb4ee6a4SAndroid Build Coastguard Worker use crate::descriptor::SafeDescriptor;
20*bb4ee6a4SAndroid Build Coastguard Worker 
21*bb4ee6a4SAndroid Build Coastguard Worker /// A trait for timer objects that delivers timer expiration
22*bb4ee6a4SAndroid Build Coastguard Worker /// notifications to an underlying descriptor.
23*bb4ee6a4SAndroid Build Coastguard Worker pub trait TimerTrait: AsRawDescriptor + IntoRawDescriptor + Send {
24*bb4ee6a4SAndroid Build Coastguard Worker     /// Sets the timer to expire after `dur` without repeating. Cancels any existing timer.
reset_oneshot(&mut self, dur: Duration) -> Result<()>25*bb4ee6a4SAndroid Build Coastguard Worker     fn reset_oneshot(&mut self, dur: Duration) -> Result<()>;
26*bb4ee6a4SAndroid Build Coastguard Worker 
27*bb4ee6a4SAndroid Build Coastguard Worker     /// Sets the timer to fire repeatedly at `dur` intervals. Cancels any existing timer.
reset_repeating(&mut self, dur: Duration) -> Result<()>28*bb4ee6a4SAndroid Build Coastguard Worker     fn reset_repeating(&mut self, dur: Duration) -> Result<()>;
29*bb4ee6a4SAndroid Build Coastguard Worker 
30*bb4ee6a4SAndroid Build Coastguard Worker     /// Waits until the timer expires.
wait(&mut self) -> Result<()>31*bb4ee6a4SAndroid Build Coastguard Worker     fn wait(&mut self) -> Result<()>;
32*bb4ee6a4SAndroid Build Coastguard Worker 
33*bb4ee6a4SAndroid Build Coastguard Worker     /// After a timer is triggered from an EventContext, mark the timer as having been waited for.
34*bb4ee6a4SAndroid Build Coastguard Worker     /// If a timer is not marked waited, it will immediately trigger the event context again. This
35*bb4ee6a4SAndroid Build Coastguard Worker     /// does not need to be called after calling Timer::wait.
36*bb4ee6a4SAndroid Build Coastguard Worker     ///
37*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns true if the timer has been adjusted since the EventContext was triggered by this
38*bb4ee6a4SAndroid Build Coastguard Worker     /// timer.
mark_waited(&mut self) -> Result<bool>39*bb4ee6a4SAndroid Build Coastguard Worker     fn mark_waited(&mut self) -> Result<bool>;
40*bb4ee6a4SAndroid Build Coastguard Worker 
41*bb4ee6a4SAndroid Build Coastguard Worker     /// Disarms the timer.
clear(&mut self) -> Result<()>42*bb4ee6a4SAndroid Build Coastguard Worker     fn clear(&mut self) -> Result<()>;
43*bb4ee6a4SAndroid Build Coastguard Worker 
44*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns the resolution of timers on the host.
resolution(&self) -> Result<Duration>45*bb4ee6a4SAndroid Build Coastguard Worker     fn resolution(&self) -> Result<Duration>;
46*bb4ee6a4SAndroid Build Coastguard Worker }
47*bb4ee6a4SAndroid Build Coastguard Worker 
48*bb4ee6a4SAndroid Build Coastguard Worker pub struct Timer {
49*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) handle: SafeDescriptor,
50*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) interval: Option<Duration>,
51*bb4ee6a4SAndroid Build Coastguard Worker }
52*bb4ee6a4SAndroid Build Coastguard Worker 
53*bb4ee6a4SAndroid Build Coastguard Worker impl Timer {
54*bb4ee6a4SAndroid Build Coastguard Worker     /// Creates a new `Timer` instance that shares the same underlying `SafeDescriptor` as the
55*bb4ee6a4SAndroid Build Coastguard Worker     /// existing `Timer` instance.
try_clone(&self) -> std::result::Result<Timer, std::io::Error>56*bb4ee6a4SAndroid Build Coastguard Worker     pub fn try_clone(&self) -> std::result::Result<Timer, std::io::Error> {
57*bb4ee6a4SAndroid Build Coastguard Worker         self.handle
58*bb4ee6a4SAndroid Build Coastguard Worker             .try_clone()
59*bb4ee6a4SAndroid Build Coastguard Worker             .map(|handle| Timer {
60*bb4ee6a4SAndroid Build Coastguard Worker                 handle,
61*bb4ee6a4SAndroid Build Coastguard Worker                 interval: self.interval,
62*bb4ee6a4SAndroid Build Coastguard Worker             })
63*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(|err| std::io::Error::from_raw_os_error(err.errno()))
64*bb4ee6a4SAndroid Build Coastguard Worker     }
65*bb4ee6a4SAndroid Build Coastguard Worker }
66*bb4ee6a4SAndroid Build Coastguard Worker 
67*bb4ee6a4SAndroid Build Coastguard Worker // This enum represents those two different retrun values from a "wait" call. Either the
68*bb4ee6a4SAndroid Build Coastguard Worker // timer will "expire", meaning it has reached it's duration, or the caller will time out
69*bb4ee6a4SAndroid Build Coastguard Worker // waiting for the timer to expire. If no timeout option is provieded to the wait call
70*bb4ee6a4SAndroid Build Coastguard Worker // then it can only return WaitResult::Expired or an error.
71*bb4ee6a4SAndroid Build Coastguard Worker #[derive(PartialEq, Eq, Debug)]
72*bb4ee6a4SAndroid Build Coastguard Worker enum WaitResult {
73*bb4ee6a4SAndroid Build Coastguard Worker     Expired,
74*bb4ee6a4SAndroid Build Coastguard Worker     Timeout,
75*bb4ee6a4SAndroid Build Coastguard Worker }
76*bb4ee6a4SAndroid Build Coastguard Worker 
77*bb4ee6a4SAndroid Build Coastguard Worker impl AsRawDescriptor for Timer {
as_raw_descriptor(&self) -> RawDescriptor78*bb4ee6a4SAndroid Build Coastguard Worker     fn as_raw_descriptor(&self) -> RawDescriptor {
79*bb4ee6a4SAndroid Build Coastguard Worker         self.handle.as_raw_descriptor()
80*bb4ee6a4SAndroid Build Coastguard Worker     }
81*bb4ee6a4SAndroid Build Coastguard Worker }
82*bb4ee6a4SAndroid Build Coastguard Worker 
83*bb4ee6a4SAndroid Build Coastguard Worker impl FromRawDescriptor for Timer {
from_raw_descriptor(handle: RawDescriptor) -> Self84*bb4ee6a4SAndroid Build Coastguard Worker     unsafe fn from_raw_descriptor(handle: RawDescriptor) -> Self {
85*bb4ee6a4SAndroid Build Coastguard Worker         Timer {
86*bb4ee6a4SAndroid Build Coastguard Worker             handle: SafeDescriptor::from_raw_descriptor(handle),
87*bb4ee6a4SAndroid Build Coastguard Worker             interval: None,
88*bb4ee6a4SAndroid Build Coastguard Worker         }
89*bb4ee6a4SAndroid Build Coastguard Worker     }
90*bb4ee6a4SAndroid Build Coastguard Worker }
91*bb4ee6a4SAndroid Build Coastguard Worker 
92*bb4ee6a4SAndroid Build Coastguard Worker impl IntoRawDescriptor for Timer {
into_raw_descriptor(self) -> RawDescriptor93*bb4ee6a4SAndroid Build Coastguard Worker     fn into_raw_descriptor(self) -> RawDescriptor {
94*bb4ee6a4SAndroid Build Coastguard Worker         self.handle.into_raw_descriptor()
95*bb4ee6a4SAndroid Build Coastguard Worker     }
96*bb4ee6a4SAndroid Build Coastguard Worker }
97*bb4ee6a4SAndroid Build Coastguard Worker 
98*bb4ee6a4SAndroid Build Coastguard Worker /// FakeTimer: For use in tests.
99*bb4ee6a4SAndroid Build Coastguard Worker pub struct FakeTimer {
100*bb4ee6a4SAndroid Build Coastguard Worker     clock: Arc<Mutex<FakeClock>>,
101*bb4ee6a4SAndroid Build Coastguard Worker     deadline_ns: Option<u64>,
102*bb4ee6a4SAndroid Build Coastguard Worker     interval: Option<Duration>,
103*bb4ee6a4SAndroid Build Coastguard Worker     event: Event,
104*bb4ee6a4SAndroid Build Coastguard Worker }
105*bb4ee6a4SAndroid Build Coastguard Worker 
106*bb4ee6a4SAndroid Build Coastguard Worker impl FakeTimer {
107*bb4ee6a4SAndroid Build Coastguard Worker     /// Creates a new fake Timer.  The timer is initally disarmed and must be armed by calling
108*bb4ee6a4SAndroid Build Coastguard Worker     /// `reset`.
new(clock: Arc<Mutex<FakeClock>>) -> Self109*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(clock: Arc<Mutex<FakeClock>>) -> Self {
110*bb4ee6a4SAndroid Build Coastguard Worker         FakeTimer {
111*bb4ee6a4SAndroid Build Coastguard Worker             clock,
112*bb4ee6a4SAndroid Build Coastguard Worker             deadline_ns: None,
113*bb4ee6a4SAndroid Build Coastguard Worker             interval: None,
114*bb4ee6a4SAndroid Build Coastguard Worker             event: Event::new().unwrap(),
115*bb4ee6a4SAndroid Build Coastguard Worker         }
116*bb4ee6a4SAndroid Build Coastguard Worker     }
117*bb4ee6a4SAndroid Build Coastguard Worker 
reset(&mut self, dur: Duration) -> Result<()>118*bb4ee6a4SAndroid Build Coastguard Worker     fn reset(&mut self, dur: Duration) -> Result<()> {
119*bb4ee6a4SAndroid Build Coastguard Worker         let mut guard = self.clock.lock();
120*bb4ee6a4SAndroid Build Coastguard Worker         let deadline = guard.nanos() + dur.as_nanos() as u64;
121*bb4ee6a4SAndroid Build Coastguard Worker         self.deadline_ns = Some(deadline);
122*bb4ee6a4SAndroid Build Coastguard Worker         guard.add_event(deadline, self.event.try_clone()?);
123*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
124*bb4ee6a4SAndroid Build Coastguard Worker     }
125*bb4ee6a4SAndroid Build Coastguard Worker 
126*bb4ee6a4SAndroid Build Coastguard Worker     /// Waits until the timer expires or an optional wait timeout expires, whichever happens first.
127*bb4ee6a4SAndroid Build Coastguard Worker     ///
128*bb4ee6a4SAndroid Build Coastguard Worker     /// # Returns
129*bb4ee6a4SAndroid Build Coastguard Worker     ///
130*bb4ee6a4SAndroid Build Coastguard Worker     /// - `WaitResult::Expired` if the timer expired.
131*bb4ee6a4SAndroid Build Coastguard Worker     /// - `WaitResult::Timeout` if `timeout` was not `None` and the timer did not expire within the
132*bb4ee6a4SAndroid Build Coastguard Worker     ///   specified timeout period.
wait_for(&mut self, timeout: Option<Duration>) -> Result<WaitResult>133*bb4ee6a4SAndroid Build Coastguard Worker     fn wait_for(&mut self, timeout: Option<Duration>) -> Result<WaitResult> {
134*bb4ee6a4SAndroid Build Coastguard Worker         let wait_start = Instant::now();
135*bb4ee6a4SAndroid Build Coastguard Worker         loop {
136*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(timeout) = timeout {
137*bb4ee6a4SAndroid Build Coastguard Worker                 let elapsed = Instant::now() - wait_start;
138*bb4ee6a4SAndroid Build Coastguard Worker                 if let Some(remaining) = elapsed.checked_sub(timeout) {
139*bb4ee6a4SAndroid Build Coastguard Worker                     if let EventWaitResult::TimedOut = self.event.wait_timeout(remaining)? {
140*bb4ee6a4SAndroid Build Coastguard Worker                         return Ok(WaitResult::Timeout);
141*bb4ee6a4SAndroid Build Coastguard Worker                     }
142*bb4ee6a4SAndroid Build Coastguard Worker                 } else {
143*bb4ee6a4SAndroid Build Coastguard Worker                     return Ok(WaitResult::Timeout);
144*bb4ee6a4SAndroid Build Coastguard Worker                 }
145*bb4ee6a4SAndroid Build Coastguard Worker             } else {
146*bb4ee6a4SAndroid Build Coastguard Worker                 self.event.wait()?;
147*bb4ee6a4SAndroid Build Coastguard Worker             }
148*bb4ee6a4SAndroid Build Coastguard Worker 
149*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(deadline_ns) = &mut self.deadline_ns {
150*bb4ee6a4SAndroid Build Coastguard Worker                 let mut guard = self.clock.lock();
151*bb4ee6a4SAndroid Build Coastguard Worker                 let now = guard.nanos();
152*bb4ee6a4SAndroid Build Coastguard Worker                 if now >= *deadline_ns {
153*bb4ee6a4SAndroid Build Coastguard Worker                     let mut expirys = 0;
154*bb4ee6a4SAndroid Build Coastguard Worker                     if let Some(interval) = self.interval {
155*bb4ee6a4SAndroid Build Coastguard Worker                         let interval_ns = interval.as_nanos() as u64;
156*bb4ee6a4SAndroid Build Coastguard Worker                         if interval_ns > 0 {
157*bb4ee6a4SAndroid Build Coastguard Worker                             expirys += (now - *deadline_ns) / interval_ns;
158*bb4ee6a4SAndroid Build Coastguard Worker                             *deadline_ns += (expirys + 1) * interval_ns;
159*bb4ee6a4SAndroid Build Coastguard Worker                             guard.add_event(*deadline_ns, self.event.try_clone()?);
160*bb4ee6a4SAndroid Build Coastguard Worker                         }
161*bb4ee6a4SAndroid Build Coastguard Worker                     }
162*bb4ee6a4SAndroid Build Coastguard Worker                     return Ok(WaitResult::Expired);
163*bb4ee6a4SAndroid Build Coastguard Worker                 }
164*bb4ee6a4SAndroid Build Coastguard Worker             }
165*bb4ee6a4SAndroid Build Coastguard Worker         }
166*bb4ee6a4SAndroid Build Coastguard Worker     }
167*bb4ee6a4SAndroid Build Coastguard Worker }
168*bb4ee6a4SAndroid Build Coastguard Worker 
169*bb4ee6a4SAndroid Build Coastguard Worker impl TimerTrait for FakeTimer {
reset_oneshot(&mut self, dur: Duration) -> Result<()>170*bb4ee6a4SAndroid Build Coastguard Worker     fn reset_oneshot(&mut self, dur: Duration) -> Result<()> {
171*bb4ee6a4SAndroid Build Coastguard Worker         self.interval = None;
172*bb4ee6a4SAndroid Build Coastguard Worker         self.reset(dur)
173*bb4ee6a4SAndroid Build Coastguard Worker     }
174*bb4ee6a4SAndroid Build Coastguard Worker 
reset_repeating(&mut self, dur: Duration) -> Result<()>175*bb4ee6a4SAndroid Build Coastguard Worker     fn reset_repeating(&mut self, dur: Duration) -> Result<()> {
176*bb4ee6a4SAndroid Build Coastguard Worker         self.interval = Some(dur);
177*bb4ee6a4SAndroid Build Coastguard Worker         self.reset(dur)
178*bb4ee6a4SAndroid Build Coastguard Worker     }
179*bb4ee6a4SAndroid Build Coastguard Worker 
wait(&mut self) -> Result<()>180*bb4ee6a4SAndroid Build Coastguard Worker     fn wait(&mut self) -> Result<()> {
181*bb4ee6a4SAndroid Build Coastguard Worker         self.wait_for(None).map(|_| ())
182*bb4ee6a4SAndroid Build Coastguard Worker     }
183*bb4ee6a4SAndroid Build Coastguard Worker 
mark_waited(&mut self) -> Result<bool>184*bb4ee6a4SAndroid Build Coastguard Worker     fn mark_waited(&mut self) -> Result<bool> {
185*bb4ee6a4SAndroid Build Coastguard Worker         // Just do a self.wait with a timeout of 0. If it times out then the timer has been
186*bb4ee6a4SAndroid Build Coastguard Worker         // adjusted.
187*bb4ee6a4SAndroid Build Coastguard Worker         if let WaitResult::Timeout = self.wait_for(Some(Duration::from_secs(0)))? {
188*bb4ee6a4SAndroid Build Coastguard Worker             Ok(true)
189*bb4ee6a4SAndroid Build Coastguard Worker         } else {
190*bb4ee6a4SAndroid Build Coastguard Worker             Ok(false)
191*bb4ee6a4SAndroid Build Coastguard Worker         }
192*bb4ee6a4SAndroid Build Coastguard Worker     }
193*bb4ee6a4SAndroid Build Coastguard Worker 
clear(&mut self) -> Result<()>194*bb4ee6a4SAndroid Build Coastguard Worker     fn clear(&mut self) -> Result<()> {
195*bb4ee6a4SAndroid Build Coastguard Worker         self.deadline_ns = None;
196*bb4ee6a4SAndroid Build Coastguard Worker         self.interval = None;
197*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
198*bb4ee6a4SAndroid Build Coastguard Worker     }
199*bb4ee6a4SAndroid Build Coastguard Worker 
resolution(&self) -> Result<Duration>200*bb4ee6a4SAndroid Build Coastguard Worker     fn resolution(&self) -> Result<Duration> {
201*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Duration::from_nanos(1))
202*bb4ee6a4SAndroid Build Coastguard Worker     }
203*bb4ee6a4SAndroid Build Coastguard Worker }
204*bb4ee6a4SAndroid Build Coastguard Worker 
205*bb4ee6a4SAndroid Build Coastguard Worker impl AsRawDescriptor for FakeTimer {
as_raw_descriptor(&self) -> RawDescriptor206*bb4ee6a4SAndroid Build Coastguard Worker     fn as_raw_descriptor(&self) -> RawDescriptor {
207*bb4ee6a4SAndroid Build Coastguard Worker         self.event.as_raw_descriptor()
208*bb4ee6a4SAndroid Build Coastguard Worker     }
209*bb4ee6a4SAndroid Build Coastguard Worker }
210*bb4ee6a4SAndroid Build Coastguard Worker impl IntoRawDescriptor for FakeTimer {
into_raw_descriptor(self) -> RawDescriptor211*bb4ee6a4SAndroid Build Coastguard Worker     fn into_raw_descriptor(self) -> RawDescriptor {
212*bb4ee6a4SAndroid Build Coastguard Worker         self.event.into_raw_descriptor()
213*bb4ee6a4SAndroid Build Coastguard Worker     }
214*bb4ee6a4SAndroid Build Coastguard Worker }
215*bb4ee6a4SAndroid Build Coastguard Worker 
216*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
217*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
218*bb4ee6a4SAndroid Build Coastguard Worker     use std::time::Duration;
219*bb4ee6a4SAndroid Build Coastguard Worker     use std::time::Instant;
220*bb4ee6a4SAndroid Build Coastguard Worker 
221*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
222*bb4ee6a4SAndroid Build Coastguard Worker     use crate::EventToken;
223*bb4ee6a4SAndroid Build Coastguard Worker     use crate::WaitContext;
224*bb4ee6a4SAndroid Build Coastguard Worker 
225*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
one_shot()226*bb4ee6a4SAndroid Build Coastguard Worker     fn one_shot() {
227*bb4ee6a4SAndroid Build Coastguard Worker         let mut tfd = Timer::new().expect("failed to create Timer");
228*bb4ee6a4SAndroid Build Coastguard Worker 
229*bb4ee6a4SAndroid Build Coastguard Worker         let dur = Duration::from_millis(10);
230*bb4ee6a4SAndroid Build Coastguard Worker         let now = Instant::now();
231*bb4ee6a4SAndroid Build Coastguard Worker         tfd.reset_oneshot(dur).expect("failed to arm timer");
232*bb4ee6a4SAndroid Build Coastguard Worker         tfd.wait().expect("unable to wait for timer");
233*bb4ee6a4SAndroid Build Coastguard Worker         let elapsed = now.elapsed();
234*bb4ee6a4SAndroid Build Coastguard Worker         assert!(elapsed >= dur, "expected {:?} >= {:?}", elapsed, dur);
235*bb4ee6a4SAndroid Build Coastguard Worker     }
236*bb4ee6a4SAndroid Build Coastguard Worker 
237*bb4ee6a4SAndroid Build Coastguard Worker     /// Similar to one_shot, except this one waits for a clone of the timer.
238*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
one_shot_cloned()239*bb4ee6a4SAndroid Build Coastguard Worker     fn one_shot_cloned() {
240*bb4ee6a4SAndroid Build Coastguard Worker         let mut tfd = Timer::new().expect("failed to create Timer");
241*bb4ee6a4SAndroid Build Coastguard Worker         let mut cloned_tfd = tfd.try_clone().expect("failed to clone timer");
242*bb4ee6a4SAndroid Build Coastguard Worker 
243*bb4ee6a4SAndroid Build Coastguard Worker         let dur = Duration::from_millis(10);
244*bb4ee6a4SAndroid Build Coastguard Worker         let now = Instant::now();
245*bb4ee6a4SAndroid Build Coastguard Worker         tfd.reset_oneshot(dur).expect("failed to arm timer");
246*bb4ee6a4SAndroid Build Coastguard Worker         cloned_tfd.wait().expect("unable to wait for timer");
247*bb4ee6a4SAndroid Build Coastguard Worker         let elapsed = now.elapsed();
248*bb4ee6a4SAndroid Build Coastguard Worker         assert!(elapsed >= dur, "expected {:?} >= {:?}", elapsed, dur);
249*bb4ee6a4SAndroid Build Coastguard Worker     }
250*bb4ee6a4SAndroid Build Coastguard Worker 
251*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
repeating()252*bb4ee6a4SAndroid Build Coastguard Worker     fn repeating() {
253*bb4ee6a4SAndroid Build Coastguard Worker         let mut tfd = Timer::new().expect("failed to create Timer");
254*bb4ee6a4SAndroid Build Coastguard Worker 
255*bb4ee6a4SAndroid Build Coastguard Worker         let interval = Duration::from_millis(10);
256*bb4ee6a4SAndroid Build Coastguard Worker         let now = Instant::now();
257*bb4ee6a4SAndroid Build Coastguard Worker         tfd.reset_repeating(interval).expect("failed to arm timer");
258*bb4ee6a4SAndroid Build Coastguard Worker 
259*bb4ee6a4SAndroid Build Coastguard Worker         tfd.wait().expect("unable to wait for timer");
260*bb4ee6a4SAndroid Build Coastguard Worker         // should take `interval` duration for the first wait
261*bb4ee6a4SAndroid Build Coastguard Worker         assert!(now.elapsed() >= interval);
262*bb4ee6a4SAndroid Build Coastguard Worker         tfd.wait().expect("unable to wait for timer");
263*bb4ee6a4SAndroid Build Coastguard Worker         // subsequent waits should take "interval" duration
264*bb4ee6a4SAndroid Build Coastguard Worker         assert!(now.elapsed() >= interval * 2);
265*bb4ee6a4SAndroid Build Coastguard Worker         tfd.wait().expect("unable to wait for timer");
266*bb4ee6a4SAndroid Build Coastguard Worker         assert!(now.elapsed() >= interval * 3);
267*bb4ee6a4SAndroid Build Coastguard Worker     }
268*bb4ee6a4SAndroid Build Coastguard Worker 
269*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
mark_waited_inactive()270*bb4ee6a4SAndroid Build Coastguard Worker     fn mark_waited_inactive() {
271*bb4ee6a4SAndroid Build Coastguard Worker         let mut tfd = Timer::new().expect("failed to create Timer");
272*bb4ee6a4SAndroid Build Coastguard Worker         // This ought to return true, but Windows always returns false, so we can't assert it here.
273*bb4ee6a4SAndroid Build Coastguard Worker         tfd.mark_waited().expect("mark_waited failed");
274*bb4ee6a4SAndroid Build Coastguard Worker     }
275*bb4ee6a4SAndroid Build Coastguard Worker 
276*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
mark_waited_active()277*bb4ee6a4SAndroid Build Coastguard Worker     fn mark_waited_active() {
278*bb4ee6a4SAndroid Build Coastguard Worker         let mut tfd = Timer::new().expect("failed to create Timer");
279*bb4ee6a4SAndroid Build Coastguard Worker         tfd.reset_oneshot(Duration::from_nanos(1))
280*bb4ee6a4SAndroid Build Coastguard Worker             .expect("failed to arm timer");
281*bb4ee6a4SAndroid Build Coastguard Worker 
282*bb4ee6a4SAndroid Build Coastguard Worker         // Use a WaitContext to block until the timer has fired.
283*bb4ee6a4SAndroid Build Coastguard Worker         #[derive(EventToken)]
284*bb4ee6a4SAndroid Build Coastguard Worker         enum Token {
285*bb4ee6a4SAndroid Build Coastguard Worker             Timer,
286*bb4ee6a4SAndroid Build Coastguard Worker         }
287*bb4ee6a4SAndroid Build Coastguard Worker         let wait_ctx: WaitContext<Token> =
288*bb4ee6a4SAndroid Build Coastguard Worker             WaitContext::build_with(&[(&tfd, Token::Timer)]).unwrap();
289*bb4ee6a4SAndroid Build Coastguard Worker         let _events = wait_ctx.wait().unwrap();
290*bb4ee6a4SAndroid Build Coastguard Worker 
291*bb4ee6a4SAndroid Build Coastguard Worker         assert!(
292*bb4ee6a4SAndroid Build Coastguard Worker             !tfd.mark_waited().expect("mark_waited failed"),
293*bb4ee6a4SAndroid Build Coastguard Worker             "expected mark_waited to return false",
294*bb4ee6a4SAndroid Build Coastguard Worker         );
295*bb4ee6a4SAndroid Build Coastguard Worker     }
296*bb4ee6a4SAndroid Build Coastguard Worker 
297*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fake_one_shot()298*bb4ee6a4SAndroid Build Coastguard Worker     fn fake_one_shot() {
299*bb4ee6a4SAndroid Build Coastguard Worker         let clock = Arc::new(Mutex::new(FakeClock::new()));
300*bb4ee6a4SAndroid Build Coastguard Worker         let mut tfd = FakeTimer::new(clock.clone());
301*bb4ee6a4SAndroid Build Coastguard Worker 
302*bb4ee6a4SAndroid Build Coastguard Worker         let dur = Duration::from_nanos(200);
303*bb4ee6a4SAndroid Build Coastguard Worker         tfd.reset_oneshot(dur).expect("failed to arm timer");
304*bb4ee6a4SAndroid Build Coastguard Worker 
305*bb4ee6a4SAndroid Build Coastguard Worker         clock.lock().add_ns(200);
306*bb4ee6a4SAndroid Build Coastguard Worker 
307*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(tfd.wait().is_ok(), true);
308*bb4ee6a4SAndroid Build Coastguard Worker     }
309*bb4ee6a4SAndroid Build Coastguard Worker 
310*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fake_one_shot_timeout()311*bb4ee6a4SAndroid Build Coastguard Worker     fn fake_one_shot_timeout() {
312*bb4ee6a4SAndroid Build Coastguard Worker         let clock = Arc::new(Mutex::new(FakeClock::new()));
313*bb4ee6a4SAndroid Build Coastguard Worker         let mut tfd = FakeTimer::new(clock.clone());
314*bb4ee6a4SAndroid Build Coastguard Worker 
315*bb4ee6a4SAndroid Build Coastguard Worker         let dur = Duration::from_nanos(200);
316*bb4ee6a4SAndroid Build Coastguard Worker         tfd.reset_oneshot(dur).expect("failed to arm timer");
317*bb4ee6a4SAndroid Build Coastguard Worker 
318*bb4ee6a4SAndroid Build Coastguard Worker         clock.lock().add_ns(100);
319*bb4ee6a4SAndroid Build Coastguard Worker         let result = tfd
320*bb4ee6a4SAndroid Build Coastguard Worker             .wait_for(Some(Duration::from_millis(0)))
321*bb4ee6a4SAndroid Build Coastguard Worker             .expect("unable to wait for timer");
322*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(result, WaitResult::Timeout);
323*bb4ee6a4SAndroid Build Coastguard Worker         let result = tfd
324*bb4ee6a4SAndroid Build Coastguard Worker             .wait_for(Some(Duration::from_millis(1)))
325*bb4ee6a4SAndroid Build Coastguard Worker             .expect("unable to wait for timer");
326*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(result, WaitResult::Timeout);
327*bb4ee6a4SAndroid Build Coastguard Worker 
328*bb4ee6a4SAndroid Build Coastguard Worker         clock.lock().add_ns(100);
329*bb4ee6a4SAndroid Build Coastguard Worker         let result = tfd
330*bb4ee6a4SAndroid Build Coastguard Worker             .wait_for(Some(Duration::from_millis(0)))
331*bb4ee6a4SAndroid Build Coastguard Worker             .expect("unable to wait for timer");
332*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(result, WaitResult::Expired);
333*bb4ee6a4SAndroid Build Coastguard Worker     }
334*bb4ee6a4SAndroid Build Coastguard Worker 
335*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fake_repeating()336*bb4ee6a4SAndroid Build Coastguard Worker     fn fake_repeating() {
337*bb4ee6a4SAndroid Build Coastguard Worker         let clock = Arc::new(Mutex::new(FakeClock::new()));
338*bb4ee6a4SAndroid Build Coastguard Worker         let mut tfd = FakeTimer::new(clock.clone());
339*bb4ee6a4SAndroid Build Coastguard Worker 
340*bb4ee6a4SAndroid Build Coastguard Worker         let interval = Duration::from_nanos(100);
341*bb4ee6a4SAndroid Build Coastguard Worker         tfd.reset_repeating(interval).expect("failed to arm timer");
342*bb4ee6a4SAndroid Build Coastguard Worker 
343*bb4ee6a4SAndroid Build Coastguard Worker         clock.lock().add_ns(150);
344*bb4ee6a4SAndroid Build Coastguard Worker 
345*bb4ee6a4SAndroid Build Coastguard Worker         // An expiration from the initial expiry and from 1 repeat.
346*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(tfd.wait().is_ok(), true);
347*bb4ee6a4SAndroid Build Coastguard Worker 
348*bb4ee6a4SAndroid Build Coastguard Worker         clock.lock().add_ns(100);
349*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(tfd.wait().is_ok(), true);
350*bb4ee6a4SAndroid Build Coastguard Worker     }
351*bb4ee6a4SAndroid Build Coastguard Worker }
352