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