xref: /aosp_15_r20/external/crosvm/base/src/timer.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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` without repeating. Cancels any existing timer.
reset_oneshot(&mut self, dur: Duration) -> Result<()>25     fn reset_oneshot(&mut self, dur: Duration) -> Result<()>;
26 
27     /// Sets the timer to fire repeatedly at `dur` intervals. Cancels any existing timer.
reset_repeating(&mut self, dur: Duration) -> Result<()>28     fn reset_repeating(&mut self, dur: Duration) -> Result<()>;
29 
30     /// Waits until the timer expires.
wait(&mut self) -> Result<()>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.
mark_waited(&mut self) -> Result<bool>39     fn mark_waited(&mut self) -> Result<bool>;
40 
41     /// Disarms the timer.
clear(&mut self) -> Result<()>42     fn clear(&mut self) -> Result<()>;
43 
44     /// Returns the resolution of timers on the host.
resolution(&self) -> Result<Duration>45     fn resolution(&self) -> Result<Duration>;
46 }
47 
48 pub struct Timer {
49     pub(crate) handle: SafeDescriptor,
50     pub(crate) interval: Option<Duration>,
51 }
52 
53 impl Timer {
54     /// Creates a new `Timer` instance that shares the same underlying `SafeDescriptor` as the
55     /// existing `Timer` instance.
try_clone(&self) -> std::result::Result<Timer, std::io::Error>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)]
72 enum WaitResult {
73     Expired,
74     Timeout,
75 }
76 
77 impl AsRawDescriptor for Timer {
as_raw_descriptor(&self) -> RawDescriptor78     fn as_raw_descriptor(&self) -> RawDescriptor {
79         self.handle.as_raw_descriptor()
80     }
81 }
82 
83 impl FromRawDescriptor for Timer {
from_raw_descriptor(handle: RawDescriptor) -> Self84     unsafe fn from_raw_descriptor(handle: RawDescriptor) -> Self {
85         Timer {
86             handle: SafeDescriptor::from_raw_descriptor(handle),
87             interval: None,
88         }
89     }
90 }
91 
92 impl IntoRawDescriptor for Timer {
into_raw_descriptor(self) -> RawDescriptor93     fn into_raw_descriptor(self) -> RawDescriptor {
94         self.handle.into_raw_descriptor()
95     }
96 }
97 
98 /// FakeTimer: For use in tests.
99 pub struct FakeTimer {
100     clock: Arc<Mutex<FakeClock>>,
101     deadline_ns: Option<u64>,
102     interval: Option<Duration>,
103     event: Event,
104 }
105 
106 impl FakeTimer {
107     /// Creates a new fake Timer.  The timer is initally disarmed and must be armed by calling
108     /// `reset`.
new(clock: Arc<Mutex<FakeClock>>) -> Self109     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 
reset(&mut self, dur: Duration) -> Result<()>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.
wait_for(&mut self, timeout: Option<Duration>) -> Result<WaitResult>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 
169 impl TimerTrait for FakeTimer {
reset_oneshot(&mut self, dur: Duration) -> Result<()>170     fn reset_oneshot(&mut self, dur: Duration) -> Result<()> {
171         self.interval = None;
172         self.reset(dur)
173     }
174 
reset_repeating(&mut self, dur: Duration) -> Result<()>175     fn reset_repeating(&mut self, dur: Duration) -> Result<()> {
176         self.interval = Some(dur);
177         self.reset(dur)
178     }
179 
wait(&mut self) -> Result<()>180     fn wait(&mut self) -> Result<()> {
181         self.wait_for(None).map(|_| ())
182     }
183 
mark_waited(&mut self) -> Result<bool>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 
clear(&mut self) -> Result<()>194     fn clear(&mut self) -> Result<()> {
195         self.deadline_ns = None;
196         self.interval = None;
197         Ok(())
198     }
199 
resolution(&self) -> Result<Duration>200     fn resolution(&self) -> Result<Duration> {
201         Ok(Duration::from_nanos(1))
202     }
203 }
204 
205 impl AsRawDescriptor for FakeTimer {
as_raw_descriptor(&self) -> RawDescriptor206     fn as_raw_descriptor(&self) -> RawDescriptor {
207         self.event.as_raw_descriptor()
208     }
209 }
210 impl IntoRawDescriptor for FakeTimer {
into_raw_descriptor(self) -> RawDescriptor211     fn into_raw_descriptor(self) -> RawDescriptor {
212         self.event.into_raw_descriptor()
213     }
214 }
215 
216 #[cfg(test)]
217 mod tests {
218     use std::time::Duration;
219     use std::time::Instant;
220 
221     use super::*;
222     use crate::EventToken;
223     use crate::WaitContext;
224 
225     #[test]
one_shot()226     fn one_shot() {
227         let mut tfd = Timer::new().expect("failed to create Timer");
228 
229         let dur = Duration::from_millis(10);
230         let now = Instant::now();
231         tfd.reset_oneshot(dur).expect("failed to arm timer");
232         tfd.wait().expect("unable to wait for timer");
233         let elapsed = now.elapsed();
234         assert!(elapsed >= dur, "expected {:?} >= {:?}", elapsed, dur);
235     }
236 
237     /// Similar to one_shot, except this one waits for a clone of the timer.
238     #[test]
one_shot_cloned()239     fn one_shot_cloned() {
240         let mut tfd = Timer::new().expect("failed to create Timer");
241         let mut cloned_tfd = tfd.try_clone().expect("failed to clone timer");
242 
243         let dur = Duration::from_millis(10);
244         let now = Instant::now();
245         tfd.reset_oneshot(dur).expect("failed to arm timer");
246         cloned_tfd.wait().expect("unable to wait for timer");
247         let elapsed = now.elapsed();
248         assert!(elapsed >= dur, "expected {:?} >= {:?}", elapsed, dur);
249     }
250 
251     #[test]
repeating()252     fn repeating() {
253         let mut tfd = Timer::new().expect("failed to create Timer");
254 
255         let interval = Duration::from_millis(10);
256         let now = Instant::now();
257         tfd.reset_repeating(interval).expect("failed to arm timer");
258 
259         tfd.wait().expect("unable to wait for timer");
260         // should take `interval` duration for the first wait
261         assert!(now.elapsed() >= interval);
262         tfd.wait().expect("unable to wait for timer");
263         // subsequent waits should take "interval" duration
264         assert!(now.elapsed() >= interval * 2);
265         tfd.wait().expect("unable to wait for timer");
266         assert!(now.elapsed() >= interval * 3);
267     }
268 
269     #[test]
mark_waited_inactive()270     fn mark_waited_inactive() {
271         let mut tfd = Timer::new().expect("failed to create Timer");
272         // This ought to return true, but Windows always returns false, so we can't assert it here.
273         tfd.mark_waited().expect("mark_waited failed");
274     }
275 
276     #[test]
mark_waited_active()277     fn mark_waited_active() {
278         let mut tfd = Timer::new().expect("failed to create Timer");
279         tfd.reset_oneshot(Duration::from_nanos(1))
280             .expect("failed to arm timer");
281 
282         // Use a WaitContext to block until the timer has fired.
283         #[derive(EventToken)]
284         enum Token {
285             Timer,
286         }
287         let wait_ctx: WaitContext<Token> =
288             WaitContext::build_with(&[(&tfd, Token::Timer)]).unwrap();
289         let _events = wait_ctx.wait().unwrap();
290 
291         assert!(
292             !tfd.mark_waited().expect("mark_waited failed"),
293             "expected mark_waited to return false",
294         );
295     }
296 
297     #[test]
fake_one_shot()298     fn fake_one_shot() {
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_oneshot(dur).expect("failed to arm timer");
304 
305         clock.lock().add_ns(200);
306 
307         assert_eq!(tfd.wait().is_ok(), true);
308     }
309 
310     #[test]
fake_one_shot_timeout()311     fn fake_one_shot_timeout() {
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         tfd.reset_oneshot(dur).expect("failed to arm timer");
317 
318         clock.lock().add_ns(100);
319         let result = tfd
320             .wait_for(Some(Duration::from_millis(0)))
321             .expect("unable to wait for timer");
322         assert_eq!(result, WaitResult::Timeout);
323         let result = tfd
324             .wait_for(Some(Duration::from_millis(1)))
325             .expect("unable to wait for timer");
326         assert_eq!(result, WaitResult::Timeout);
327 
328         clock.lock().add_ns(100);
329         let result = tfd
330             .wait_for(Some(Duration::from_millis(0)))
331             .expect("unable to wait for timer");
332         assert_eq!(result, WaitResult::Expired);
333     }
334 
335     #[test]
fake_repeating()336     fn fake_repeating() {
337         let clock = Arc::new(Mutex::new(FakeClock::new()));
338         let mut tfd = FakeTimer::new(clock.clone());
339 
340         let interval = Duration::from_nanos(100);
341         tfd.reset_repeating(interval).expect("failed to arm timer");
342 
343         clock.lock().add_ns(150);
344 
345         // An expiration from the initial expiry and from 1 repeat.
346         assert_eq!(tfd.wait().is_ok(), true);
347 
348         clock.lock().add_ns(100);
349         assert_eq!(tfd.wait().is_ok(), true);
350     }
351 }
352