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