Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/base/src/sys/windows/timer.rs
5394 views
1
// Copyright 2022 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::os::windows::io::AsRawHandle;
6
use std::os::windows::io::RawHandle;
7
use std::ptr;
8
use std::time::Duration;
9
10
use win_util::LargeInteger;
11
use win_util::SecurityAttributes;
12
use win_util::SelfRelativeSecurityDescriptor;
13
use winapi::shared::minwindef::FALSE;
14
use winapi::um::synchapi::CancelWaitableTimer;
15
use winapi::um::synchapi::SetWaitableTimer;
16
use winapi::um::synchapi::WaitForSingleObject;
17
use winapi::um::winbase::CreateWaitableTimerA;
18
use winapi::um::winbase::INFINITE;
19
use winapi::um::winbase::WAIT_OBJECT_0;
20
21
use super::errno_result;
22
use super::platform_timer_utils::nt_query_timer_resolution;
23
use super::Result;
24
use crate::descriptor::AsRawDescriptor;
25
use crate::descriptor::FromRawDescriptor;
26
use crate::descriptor::SafeDescriptor;
27
use crate::timer::Timer;
28
use crate::timer::TimerTrait;
29
30
impl AsRawHandle for Timer {
31
fn as_raw_handle(&self) -> RawHandle {
32
self.handle.as_raw_descriptor()
33
}
34
}
35
36
impl Timer {
37
/// Creates a new timer. The timer is initally disarmed and must be armed by calling
38
/// `reset`. Note that this timer MAY wake/trigger early due to limitations on
39
/// SetWaitableTimer (see <https://github.com/rust-lang/rust/issues/43376>).
40
pub fn new() -> Result<Timer> {
41
// SAFETY:
42
// Safe because this doesn't modify any memory and we check the return value.
43
let handle = unsafe {
44
CreateWaitableTimerA(
45
// Not inheritable, duplicate before passing to child prcesses
46
SecurityAttributes::new_with_security_descriptor(
47
SelfRelativeSecurityDescriptor::get_singleton(),
48
/* inherit= */ false,
49
)
50
.as_mut(),
51
// This is a synchronization timer, not a manual-reset timer.
52
FALSE,
53
// TODO (colindr) b/145622516 - we may have to give this a name if we later
54
// want to use names to test object equality
55
ptr::null_mut(),
56
)
57
};
58
59
if handle.is_null() {
60
return errno_result();
61
}
62
63
Ok(Timer {
64
// SAFETY:
65
// Safe because we uniquely own the file descriptor.
66
handle: unsafe { SafeDescriptor::from_raw_descriptor(handle) },
67
interval: None,
68
})
69
}
70
71
fn reset(&mut self, dur: Duration, mut interval: Option<Duration>) -> Result<()> {
72
// If interval is 0 or None it means that this timer does not repeat. We
73
// set self.interval to None in this case so it can easily be checked
74
// in self.wait.
75
if interval == Some(Duration::from_secs(0)) {
76
interval = None;
77
}
78
self.interval = interval;
79
// Windows timers use negative values for relative times, and positive
80
// values for absolute times, so we'll use negative times.
81
82
// Windows timers also use a 64 number of 100 nanosecond intervals,
83
// which we get like so: (dur.as_secs()*1e7 + dur.subsec_nanos()/100)
84
85
let due_time = LargeInteger::new(
86
-((dur.as_secs() * 10_000_000 + (dur.subsec_nanos() as u64) / 100) as i64),
87
);
88
let period: i32 = match interval {
89
Some(int) => {
90
if int.is_zero() {
91
// Duration of zero implies non-periodic, which means setting period
92
// to 0ms.
93
0
94
} else {
95
// Otherwise, convert to ms and make sure it's >=1ms.
96
std::cmp::max(1, int.as_millis() as i32)
97
}
98
}
99
// Period of 0ms=non-periodic.
100
None => 0,
101
};
102
103
// SAFETY:
104
// Safe because this doesn't modify any memory and we check the return value.
105
let ret = unsafe {
106
SetWaitableTimer(
107
self.as_raw_descriptor(),
108
&*due_time,
109
period,
110
None, // no completion routine
111
ptr::null_mut(), // or routine argument
112
FALSE, // no restoring system from power conservation mode
113
)
114
};
115
if ret == 0 {
116
return errno_result();
117
}
118
119
Ok(())
120
}
121
}
122
123
impl TimerTrait for Timer {
124
fn reset_oneshot(&mut self, dur: Duration) -> Result<()> {
125
self.reset(dur, None)
126
}
127
128
fn reset_repeating(&mut self, interval: Duration) -> Result<()> {
129
self.reset(interval, Some(interval))
130
}
131
132
fn wait(&mut self) -> Result<()> {
133
// SAFETY:
134
// Safe because this doesn't modify any memory and we check the return value.
135
let ret = unsafe { WaitForSingleObject(self.as_raw_descriptor(), INFINITE) };
136
137
// Should return WAIT_OBJECT_0, otherwise it's some sort of error or
138
// timeout (which shouldn't happen in this case).
139
match ret {
140
WAIT_OBJECT_0 => Ok(()),
141
_ => errno_result(),
142
}
143
}
144
145
fn mark_waited(&mut self) -> Result<bool> {
146
// We use a synchronization timer on windows, meaning waiting on the timer automatically
147
// un-signals the timer. We assume this is atomic so the return value is always false.
148
Ok(false)
149
}
150
151
fn clear(&mut self) -> Result<()> {
152
// SAFETY:
153
// Safe because this doesn't modify any memory and we check the return value.
154
let ret = unsafe { CancelWaitableTimer(self.as_raw_descriptor()) };
155
156
if ret == 0 {
157
return errno_result();
158
}
159
160
self.interval = None;
161
Ok(())
162
}
163
164
fn resolution(&self) -> Result<Duration> {
165
nt_query_timer_resolution().map(|(current_res, _)| current_res)
166
}
167
}
168
169