• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 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::{
6     sync::Arc,
7     time::{Duration, Instant},
8 };
9 use sync::Mutex;
10 
11 use super::{Event, EventReadResult, FakeClock, RawDescriptor, Result};
12 use crate::descriptor::{AsRawDescriptor, FromRawDescriptor, IntoRawDescriptor, SafeDescriptor};
13 
14 #[path = "win/timer.rs"]
15 mod timer_platform;
16 
17 pub struct Timer {
18     handle: SafeDescriptor,
19     interval: Option<Duration>,
20 }
21 
22 impl Timer {
23     /// Creates a new `Timer` instance that shares the same underlying `SafeDescriptor` as the
24     /// existing `Timer` instance.
try_clone(&self) -> std::result::Result<Timer, std::io::Error>25     pub fn try_clone(&self) -> std::result::Result<Timer, std::io::Error> {
26         self.handle
27             .try_clone()
28             .map(|handle| Timer {
29                 handle,
30                 interval: self.interval,
31             })
32             .map_err(|err| std::io::Error::from_raw_os_error(err.errno()))
33     }
34 }
35 
36 // This enum represents those two different retrun values from a "wait" call. Either the
37 // timer will "expire", meaning it has reached it's duration, or the caller will time out
38 // waiting for the timer to expire. If no timeout option is provieded to the wait call
39 // then it can only return WaitResult::Expired or an error.
40 #[derive(PartialEq, Debug)]
41 pub enum WaitResult {
42     Expired,
43     Timeout,
44 }
45 
46 impl AsRawDescriptor for Timer {
as_raw_descriptor(&self) -> RawDescriptor47     fn as_raw_descriptor(&self) -> RawDescriptor {
48         self.handle.as_raw_descriptor()
49     }
50 }
51 
52 impl FromRawDescriptor for Timer {
from_raw_descriptor(handle: RawDescriptor) -> Self53     unsafe fn from_raw_descriptor(handle: RawDescriptor) -> Self {
54         Timer {
55             handle: SafeDescriptor::from_raw_descriptor(handle),
56             interval: None,
57         }
58     }
59 }
60 
61 impl IntoRawDescriptor for Timer {
into_raw_descriptor(self) -> RawDescriptor62     fn into_raw_descriptor(self) -> RawDescriptor {
63         self.handle.into_raw_descriptor()
64     }
65 }
66 
67 /// FakeTimer: For use in tests.
68 pub struct FakeTimer {
69     clock: Arc<Mutex<FakeClock>>,
70     deadline_ns: Option<u64>,
71     interval: Option<Duration>,
72     event: Event,
73 }
74 
75 impl FakeTimer {
76     /// Creates a new fake Timer.  The timer is initally disarmed and must be armed by calling
77     /// `reset`.
new(clock: Arc<Mutex<FakeClock>>) -> Self78     pub fn new(clock: Arc<Mutex<FakeClock>>) -> Self {
79         FakeTimer {
80             clock,
81             deadline_ns: None,
82             interval: None,
83             event: Event::new().unwrap(),
84         }
85     }
86 
87     /// Sets the timer to expire after `dur`.  If `interval` is not `None` it represents
88     /// the period for repeated expirations after the initial expiration.  Otherwise
89     /// the timer will expire just once.  Cancels any existing duration and repeating interval.
reset(&mut self, dur: Duration, interval: Option<Duration>) -> Result<()>90     pub fn reset(&mut self, dur: Duration, interval: Option<Duration>) -> Result<()> {
91         let mut guard = self.clock.lock();
92         let deadline = guard.nanos() + dur.as_nanos() as u64;
93         self.deadline_ns = Some(deadline);
94         self.interval = interval;
95         guard.add_event(deadline, self.event.try_clone()?);
96         Ok(())
97     }
98 
99     /// Waits until the timer expires, returning WaitResult::Expired when it expires.
100     ///
101     /// If timeout is not None, block for a maximum of the given `timeout` duration.
102     /// If a timeout occurs, return WaitResult::Timeout.
wait(&mut self, timeout: Option<Duration>) -> Result<WaitResult>103     pub fn wait(&mut self, timeout: Option<Duration>) -> Result<WaitResult> {
104         let wait_start = Instant::now();
105         loop {
106             if let Some(timeout) = timeout {
107                 let elapsed = Instant::now() - wait_start;
108                 if let Some(remaining) = elapsed.checked_sub(timeout) {
109                     if let EventReadResult::Timeout = self.event.read_timeout(remaining)? {
110                         return Ok(WaitResult::Timeout);
111                     }
112                 } else {
113                     return Ok(WaitResult::Timeout);
114                 }
115             } else {
116                 self.event.read()?;
117             }
118 
119             if let Some(deadline_ns) = &mut self.deadline_ns {
120                 let mut guard = self.clock.lock();
121                 let now = guard.nanos();
122                 if now >= *deadline_ns {
123                     let mut expirys = 0;
124                     if let Some(interval) = self.interval {
125                         let interval_ns = interval.as_nanos() as u64;
126                         if interval_ns > 0 {
127                             expirys += (now - *deadline_ns) / interval_ns;
128                             *deadline_ns += (expirys + 1) * interval_ns;
129                             guard.add_event(*deadline_ns, self.event.try_clone()?);
130                         }
131                     }
132                     return Ok(WaitResult::Expired);
133                 }
134             }
135         }
136     }
137 
138     /// After a timer is triggered from an EventContext, mark the timer as having been waited for.
139     /// If a timer is not marked waited, it will immediately trigger the event context again. This
140     /// does not need to be called after calling Timer::wait.
141     ///
142     /// Returns true if the timer has been adjusted since the EventContext was triggered by this
143     /// timer.
mark_waited(&mut self) -> Result<bool>144     pub fn mark_waited(&mut self) -> Result<bool> {
145         // Just do a self.wait with a timeout of 0. If it times out then the timer has been
146         // adjusted.
147         if let WaitResult::Timeout = self.wait(Some(Duration::from_secs(0)))? {
148             Ok(true)
149         } else {
150             Ok(false)
151         }
152     }
153 
154     /// Disarms the timer.
clear(&mut self) -> Result<()>155     pub fn clear(&mut self) -> Result<()> {
156         self.deadline_ns = None;
157         self.interval = None;
158         Ok(())
159     }
160 
161     /// Returns the resolution of timers on the host.
resolution() -> Result<Duration>162     pub fn resolution() -> Result<Duration> {
163         Ok(Duration::from_nanos(1))
164     }
165 }
166 
167 impl AsRawDescriptor for FakeTimer {
as_raw_descriptor(&self) -> RawDescriptor168     fn as_raw_descriptor(&self) -> RawDescriptor {
169         self.event.as_raw_descriptor()
170     }
171 }
172 impl IntoRawDescriptor for FakeTimer {
into_raw_descriptor(self) -> RawDescriptor173     fn into_raw_descriptor(self) -> RawDescriptor {
174         self.event.into_raw_descriptor()
175     }
176 }
177 
178 #[cfg(test)]
179 mod tests {
180     use super::*;
181     use std::time::{Duration, Instant};
182 
183     // clock error is 2*clock_resolution + 100 microseconds to handle
184     // time change from calling now() to arming timer
get_clock_error() -> Duration185     fn get_clock_error() -> Duration {
186         Timer::resolution()
187             .expect("expected to be able to read timer resolution")
188             .checked_mul(2)
189             .expect("timer resolution x 2 should not overflow")
190             .checked_add(Duration::from_micros(100))
191             .expect("timer resolution x 2 + 100 microsecond should not overflow")
192     }
193 
194     #[test]
195     #[ignore]
one_shot()196     fn one_shot() {
197         // This test relies on the host having a reliable clock and not being
198         // overloaded, so it's marked as "ignore".  You can run by running
199         // cargo test -p win_sys_util timer -- --ignored
200 
201         let mut tfd = Timer::new().expect("failed to create Timer");
202 
203         let dur = Duration::from_millis(1000);
204         let clock_error = get_clock_error();
205 
206         let now = Instant::now();
207         tfd.reset(dur, None).expect("failed to arm timer");
208 
209         tfd.wait(None).expect("unable to wait for timer");
210         let elapsed = now.elapsed();
211         // elapsed is within +-clock_error from expected duration
212         assert!(elapsed - clock_error <= dur);
213         assert!(elapsed + clock_error >= dur);
214     }
215 
216     /// Similar to one_shot, except this one waits for a clone of the timer.
217     #[test]
218     #[ignore]
one_shot_cloned()219     fn one_shot_cloned() {
220         let mut tfd = Timer::new().expect("failed to create Timer");
221         let dur = Duration::from_millis(1000);
222         let mut cloned_tfd = tfd.try_clone().expect("failed to clone timer");
223 
224         // clock error is 2*clock_resolution + 100 microseconds to handle
225         // time change from calling now() to arming timer
226         let clock_error = get_clock_error();
227 
228         let now = Instant::now();
229         tfd.reset(dur, None).expect("failed to arm timer");
230         cloned_tfd.wait(None).expect("unable to wait for timer");
231         let elapsed = now.elapsed();
232 
233         // elapsed is within +-clock_error from expected duration
234         assert!(elapsed - clock_error <= dur);
235         assert!(elapsed + clock_error >= dur);
236     }
237 
238     #[test]
239     #[ignore]
repeating()240     fn repeating() {
241         // This test relies on the host having a reliable clock and not being
242         // overloaded, so it's marked as "ignore".  You can run by running
243         // cargo test -p win_sys_util timer -- --ignored
244 
245         let mut tfd = Timer::new().expect("failed to create Timer");
246 
247         let dur = Duration::from_millis(200);
248         // clock error is 2*clock_resolution + 100 microseconds to handle
249         // time change from calling now() to arming timer
250         let clock_error = Timer::resolution()
251             .expect("expected to be able to read timer resolution")
252             .checked_mul(2)
253             .expect("timer resolution x 2 should not overflow")
254             .checked_add(Duration::from_micros(100))
255             .expect("timer resolution x 2 + 100 microsecond should not overflow");
256         let interval = Duration::from_millis(100);
257         let now = Instant::now();
258         tfd.reset(dur, Some(interval)).expect("failed to arm timer");
259 
260         tfd.wait(None).expect("unable to wait for timer");
261         // should take "dur" duration for the first wait
262         assert!(now.elapsed() + clock_error >= dur);
263         tfd.wait(None).expect("unable to wait for timer");
264         // subsequent waits should take "interval" duration
265         assert!(now.elapsed() + clock_error >= dur + interval);
266         tfd.wait(None).expect("unable to wait for timer");
267         assert!(now.elapsed() + clock_error >= dur + interval * 2);
268     }
269 
270     #[test]
fake_one_shot()271     fn fake_one_shot() {
272         let clock = Arc::new(Mutex::new(FakeClock::new()));
273         let mut tfd = FakeTimer::new(clock.clone());
274 
275         let dur = Duration::from_nanos(200);
276         tfd.reset(dur, None).expect("failed to arm timer");
277 
278         clock.lock().add_ns(200);
279 
280         let result = tfd.wait(None).expect("unable to wait for timer");
281 
282         assert_eq!(result, WaitResult::Expired);
283     }
284 
285     #[test]
fake_one_shot_timeout()286     fn fake_one_shot_timeout() {
287         let clock = Arc::new(Mutex::new(FakeClock::new()));
288         let mut tfd = FakeTimer::new(clock.clone());
289 
290         let dur = Duration::from_nanos(200);
291         tfd.reset(dur, None).expect("failed to arm timer");
292 
293         clock.lock().add_ns(100);
294         let result = tfd
295             .wait(Some(Duration::from_millis(0)))
296             .expect("unable to wait for timer");
297         assert_eq!(result, WaitResult::Timeout);
298         let result = tfd
299             .wait(Some(Duration::from_millis(1)))
300             .expect("unable to wait for timer");
301         assert_eq!(result, WaitResult::Timeout);
302 
303         clock.lock().add_ns(100);
304         let result = tfd
305             .wait(Some(Duration::from_millis(0)))
306             .expect("unable to wait for timer");
307         assert_eq!(result, WaitResult::Expired);
308     }
309 
310     #[test]
fake_repeating()311     fn fake_repeating() {
312         let clock = Arc::new(Mutex::new(FakeClock::new()));
313         let mut tfd = FakeTimer::new(clock.clone());
314 
315         let dur = Duration::from_nanos(200);
316         let interval = Duration::from_nanos(100);
317         tfd.reset(dur, Some(interval)).expect("failed to arm timer");
318 
319         clock.lock().add_ns(300);
320 
321         let mut result = tfd.wait(None).expect("unable to wait for timer");
322         // An expiration from the initial expiry and from 1 repeat.
323         assert_eq!(result, WaitResult::Expired);
324 
325         clock.lock().add_ns(300);
326         result = tfd.wait(None).expect("unable to wait for timer");
327         assert_eq!(result, WaitResult::Expired);
328     }
329 
330     #[test]
331     #[ignore]
zero_interval()332     fn zero_interval() {
333         // This test relies on the host having a reliable clock and not being
334         // overloaded, so it's marked as "ignore".  You can run by running
335         // cargo test -p win_sys_util timer -- --ignored
336 
337         let mut tfd = Timer::new().expect("failed to create timer");
338 
339         let dur = Duration::from_nanos(200);
340         // interval is 0, so should not repeat
341         let interval = Duration::from_nanos(0);
342 
343         tfd.reset(dur, Some(interval)).expect("failed to arm timer");
344 
345         // should wait successfully the first time
346         tfd.wait(None).expect("unable to wait for timer");
347 
348         // now this wait should timeout
349         let wr = tfd
350             .wait(Some(Duration::from_secs(1)))
351             .expect("unable to wait on timer");
352 
353         assert_eq!(wr, WaitResult::Timeout);
354     }
355 }
356