Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/base/src/sys/windows/event.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::ffi::CString;
6
use std::os::windows::io::AsRawHandle;
7
use std::os::windows::io::RawHandle;
8
use std::ptr::null;
9
use std::time::Duration;
10
11
use serde::Deserialize;
12
use serde::Serialize;
13
use win_util::SecurityAttributes;
14
use win_util::SelfRelativeSecurityDescriptor;
15
use winapi::shared::minwindef::DWORD;
16
use winapi::shared::minwindef::FALSE;
17
use winapi::shared::minwindef::TRUE;
18
use winapi::shared::winerror::WAIT_TIMEOUT;
19
use winapi::um::handleapi::DuplicateHandle;
20
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
21
use winapi::um::processthreadsapi::GetCurrentProcess;
22
use winapi::um::synchapi::CreateEventA;
23
use winapi::um::synchapi::OpenEventA;
24
use winapi::um::synchapi::ResetEvent;
25
use winapi::um::synchapi::SetEvent;
26
use winapi::um::synchapi::WaitForSingleObject;
27
use winapi::um::winbase::INFINITE;
28
use winapi::um::winbase::WAIT_FAILED;
29
use winapi::um::winbase::WAIT_OBJECT_0;
30
use winapi::um::winnt::DUPLICATE_SAME_ACCESS;
31
use winapi::um::winnt::EVENT_MODIFY_STATE;
32
33
use super::errno_result;
34
use super::Error;
35
use super::RawDescriptor;
36
use super::Result;
37
use crate::descriptor::AsRawDescriptor;
38
use crate::descriptor::FromRawDescriptor;
39
use crate::descriptor::IntoRawDescriptor;
40
use crate::descriptor::SafeDescriptor;
41
use crate::Event;
42
use crate::EventWaitResult;
43
44
/// A safe wrapper around Windows synchapi methods used to mimic Linux eventfd (man 2 eventfd).
45
/// Since the eventfd isn't using "EFD_SEMAPHORE", we don't need to keep count so we can just use
46
/// events.
47
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
48
#[serde(transparent)]
49
pub(crate) struct PlatformEvent {
50
event_handle: SafeDescriptor,
51
}
52
53
pub trait EventExt {
54
fn new_auto_reset() -> Result<Event>;
55
fn open(name: &str) -> Result<Event>;
56
fn create_event_with_name(name: &str) -> Result<Event>;
57
}
58
59
impl EventExt for Event {
60
fn new_auto_reset() -> Result<Event> {
61
PlatformEvent::new_with_manual_reset(false).map(Event)
62
}
63
64
fn open(name: &str) -> Result<Event> {
65
PlatformEvent::open(name).map(Event)
66
}
67
68
fn create_event_with_name(name: &str) -> Result<Event> {
69
PlatformEvent::create_event_with_name(name).map(Event)
70
}
71
}
72
73
impl PlatformEvent {
74
pub fn new_with_manual_reset(manual_reset: bool) -> Result<PlatformEvent> {
75
// SAFETY: Safe because return value is checked.
76
let handle = unsafe {
77
CreateEventA(
78
SecurityAttributes::new_with_security_descriptor(
79
SelfRelativeSecurityDescriptor::get_singleton(),
80
/* inherit= */ false,
81
)
82
.as_mut(),
83
if manual_reset { TRUE } else { FALSE },
84
FALSE, // initial state = unsignalled
85
null(),
86
)
87
};
88
if handle.is_null() {
89
return errno_result();
90
}
91
Ok(PlatformEvent {
92
event_handle:
93
// SAFETY: Safe because the descriptor is valid.
94
unsafe { SafeDescriptor::from_raw_descriptor(handle) },
95
})
96
}
97
98
pub fn create_event_with_name(name: &str) -> Result<PlatformEvent> {
99
let event_str = CString::new(String::from(name)).unwrap();
100
// SAFETY: Safe because return value is checked.
101
let handle = unsafe {
102
CreateEventA(
103
SecurityAttributes::new_with_security_descriptor(
104
SelfRelativeSecurityDescriptor::get_singleton(),
105
/* inherit= */ false,
106
)
107
.as_mut(),
108
FALSE, // manual_reset = false
109
FALSE, // initial state = unsignalled
110
event_str.as_ptr(),
111
)
112
};
113
if handle.is_null() {
114
return errno_result();
115
}
116
Ok(PlatformEvent {
117
event_handle:
118
// SAFETY: Safe because the descriptor is valid.
119
unsafe { SafeDescriptor::from_raw_descriptor(handle) },
120
})
121
}
122
123
pub fn new() -> Result<PlatformEvent> {
124
// Require manual reset
125
PlatformEvent::new_with_manual_reset(true)
126
}
127
128
pub fn open(name: &str) -> Result<PlatformEvent> {
129
let event_str = CString::new(String::from(name)).unwrap();
130
// SAFETY: Safe because return value is checked.
131
let handle = unsafe { OpenEventA(EVENT_MODIFY_STATE, FALSE, event_str.as_ptr()) };
132
if handle.is_null() {
133
return errno_result();
134
}
135
Ok(PlatformEvent {
136
event_handle:
137
// SAFETY: Safe because the descriptor is valid.
138
unsafe { SafeDescriptor::from_raw_descriptor(handle) },
139
})
140
}
141
142
/// See `Event::signal`.
143
pub fn signal(&self) -> Result<()> {
144
// SAFETY: Safe because the descriptor is valid.
145
let event_result = unsafe { SetEvent(self.event_handle.as_raw_descriptor()) };
146
if event_result == 0 {
147
return errno_result();
148
}
149
Ok(())
150
}
151
152
pub fn reset(&self) -> Result<()> {
153
// SAFETY: Safe because the descriptor is valid.
154
let res = unsafe { ResetEvent(self.event_handle.as_raw_descriptor()) };
155
if res == 0 {
156
errno_result()
157
} else {
158
Ok(())
159
}
160
}
161
162
/// Wait for the event with an optional timeout and reset the event if it was signaled.
163
fn wait_and_reset(&self, timeout: Option<Duration>) -> Result<EventWaitResult> {
164
let milliseconds = match timeout {
165
Some(timeout) => timeout.as_millis() as DWORD,
166
None => INFINITE,
167
};
168
169
// SAFETY:
170
// Safe because we pass an event object handle owned by this PlatformEvent.
171
let wait_result = match unsafe {
172
WaitForSingleObject(self.event_handle.as_raw_descriptor(), milliseconds)
173
} {
174
WAIT_OBJECT_0 => Ok(EventWaitResult::Signaled),
175
WAIT_TIMEOUT => Ok(EventWaitResult::TimedOut),
176
WAIT_FAILED => errno_result(),
177
other => Err(Error::new(other)),
178
}?;
179
180
if wait_result == EventWaitResult::Signaled {
181
self.reset()?;
182
}
183
184
Ok(wait_result)
185
}
186
187
/// See `Event::wait`.
188
pub fn wait(&self) -> Result<()> {
189
let wait_result = self.wait_and_reset(None)?;
190
// Waiting with `INFINITE` can only return when the event is signaled or an error occurs.
191
// `EventWaitResult::TimedOut` is not valid here.
192
assert_eq!(wait_result, EventWaitResult::Signaled);
193
Ok(())
194
}
195
196
/// See `Event::wait_timeout`.
197
pub fn wait_timeout(&self, timeout: Duration) -> Result<EventWaitResult> {
198
self.wait_and_reset(Some(timeout))
199
}
200
201
pub fn try_clone(&self) -> Result<PlatformEvent> {
202
let mut event_clone = INVALID_HANDLE_VALUE;
203
// SAFETY: Safe because return value is checked.
204
let duplicate_result = unsafe {
205
DuplicateHandle(
206
GetCurrentProcess(),
207
self.event_handle.as_raw_descriptor(),
208
GetCurrentProcess(),
209
&mut event_clone,
210
0,
211
0,
212
DUPLICATE_SAME_ACCESS,
213
)
214
};
215
if duplicate_result == 0 {
216
return errno_result();
217
}
218
Ok(
219
// SAFETY: Safe because the descriptor is valid.
220
unsafe { PlatformEvent::from_raw_descriptor(event_clone) },
221
)
222
}
223
}
224
225
impl AsRawDescriptor for PlatformEvent {
226
fn as_raw_descriptor(&self) -> RawDescriptor {
227
self.event_handle.as_raw_descriptor()
228
}
229
}
230
231
impl FromRawDescriptor for PlatformEvent {
232
// SAFETY: Safe because the descriptor is expected to be valid.
233
unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
234
PlatformEvent {
235
event_handle: SafeDescriptor::from_raw_descriptor(descriptor),
236
}
237
}
238
}
239
240
impl AsRawHandle for PlatformEvent {
241
fn as_raw_handle(&self) -> RawHandle {
242
self.as_raw_descriptor()
243
}
244
}
245
246
impl IntoRawDescriptor for PlatformEvent {
247
fn into_raw_descriptor(self) -> RawDescriptor {
248
self.event_handle.into_raw_descriptor()
249
}
250
}
251
252
impl From<PlatformEvent> for SafeDescriptor {
253
fn from(evt: PlatformEvent) -> Self {
254
evt.event_handle
255
}
256
}
257
258
impl From<SafeDescriptor> for PlatformEvent {
259
fn from(sd: SafeDescriptor) -> Self {
260
PlatformEvent { event_handle: sd }
261
}
262
}
263
264
// Safety:
265
// PlatformEvent is safe for send & Sync despite containing a raw handle to its
266
// file mapping object. As long as the instance to PlatformEvent stays alive, this
267
// pointer will be a valid handle.
268
unsafe impl Send for PlatformEvent {}
269
// Safety: See comments for impl Send
270
unsafe impl Sync for PlatformEvent {}
271
272
#[cfg(test)]
273
mod tests {
274
use winapi::shared::winerror::WAIT_TIMEOUT;
275
use winapi::um::winbase::INFINITE;
276
use winapi::um::winbase::WAIT_OBJECT_0;
277
278
use super::*;
279
280
#[test]
281
fn new() {
282
PlatformEvent::new().unwrap();
283
}
284
285
#[test]
286
fn read_write() {
287
let evt = PlatformEvent::new().unwrap();
288
evt.signal().unwrap();
289
assert_eq!(evt.wait(), Ok(()));
290
}
291
292
#[test]
293
fn read_write_auto_reset() {
294
let evt = PlatformEvent::new_with_manual_reset(false).unwrap();
295
evt.signal().unwrap();
296
297
// Wait for the notification.
298
// SAFETY: Safe because return value is checked.
299
let result = unsafe { WaitForSingleObject(evt.as_raw_descriptor(), INFINITE) };
300
assert_eq!(result, WAIT_OBJECT_0);
301
302
// The notification should have reset since we already received it.
303
// SAFETY: Safe because return value is checked.
304
let result = unsafe { WaitForSingleObject(evt.as_raw_descriptor(), 0) };
305
assert_eq!(result, WAIT_TIMEOUT);
306
}
307
308
#[test]
309
fn read_write_notifies_until_read() {
310
let evt = PlatformEvent::new().unwrap();
311
evt.signal().unwrap();
312
313
// Wait for the notification.
314
// SAFETY: Safe because return value is checked.
315
let result = unsafe { WaitForSingleObject(evt.as_raw_descriptor(), INFINITE) };
316
assert_eq!(result, WAIT_OBJECT_0);
317
318
// The notification should still be active because read wasn't called.
319
// SAFETY: Safe because return value is checked.
320
let result = unsafe { WaitForSingleObject(evt.as_raw_descriptor(), 0) };
321
assert_eq!(result, WAIT_OBJECT_0);
322
323
// Read and ensure the notification has cleared.
324
evt.wait().expect("Failed to read event.");
325
// SAFETY: Safe because return value is checked.
326
let result = unsafe { WaitForSingleObject(evt.as_raw_descriptor(), 0) };
327
assert_eq!(result, WAIT_TIMEOUT);
328
}
329
330
#[test]
331
fn clone() {
332
let evt = PlatformEvent::new().unwrap();
333
let evt_clone = evt.try_clone().unwrap();
334
evt.signal().unwrap();
335
assert_eq!(evt_clone.wait(), Ok(()));
336
}
337
338
#[test]
339
fn timeout() {
340
let evt = PlatformEvent::new().expect("failed to create event");
341
assert_eq!(
342
evt.wait_timeout(Duration::from_millis(1))
343
.expect("failed to read from event with timeout"),
344
EventWaitResult::TimedOut
345
);
346
}
347
}
348
349