base/
timer.rs

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