Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/base/src/timer.rs
5394 views
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.
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
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.
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 {
78
fn as_raw_descriptor(&self) -> RawDescriptor {
79
self.handle.as_raw_descriptor()
80
}
81
}
82
83
impl 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
92
impl 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.
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`.
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
169
impl 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
205
impl AsRawDescriptor for FakeTimer {
206
fn as_raw_descriptor(&self) -> RawDescriptor {
207
self.event.as_raw_descriptor()
208
}
209
}
210
impl IntoRawDescriptor for FakeTimer {
211
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
#[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
}
356
357