xref: /aosp_15_r20/external/crosvm/base/src/sys/windows/wait.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use std::cmp::min;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::HashMap;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::os::windows::io::RawHandle;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
10*bb4ee6a4SAndroid Build Coastguard Worker 
11*bb4ee6a4SAndroid Build Coastguard Worker use smallvec::SmallVec;
12*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
13*bb4ee6a4SAndroid Build Coastguard Worker use winapi::shared::minwindef::DWORD;
14*bb4ee6a4SAndroid Build Coastguard Worker use winapi::shared::minwindef::FALSE;
15*bb4ee6a4SAndroid Build Coastguard Worker use winapi::shared::winerror::ERROR_INVALID_PARAMETER;
16*bb4ee6a4SAndroid Build Coastguard Worker use winapi::shared::winerror::WAIT_TIMEOUT;
17*bb4ee6a4SAndroid Build Coastguard Worker use winapi::um::synchapi::WaitForMultipleObjects;
18*bb4ee6a4SAndroid Build Coastguard Worker use winapi::um::winbase::WAIT_OBJECT_0;
19*bb4ee6a4SAndroid Build Coastguard Worker 
20*bb4ee6a4SAndroid Build Coastguard Worker use super::errno_result;
21*bb4ee6a4SAndroid Build Coastguard Worker use super::Error;
22*bb4ee6a4SAndroid Build Coastguard Worker use super::EventTrigger;
23*bb4ee6a4SAndroid Build Coastguard Worker use super::Result;
24*bb4ee6a4SAndroid Build Coastguard Worker use crate::descriptor::AsRawDescriptor;
25*bb4ee6a4SAndroid Build Coastguard Worker use crate::descriptor::Descriptor;
26*bb4ee6a4SAndroid Build Coastguard Worker use crate::error;
27*bb4ee6a4SAndroid Build Coastguard Worker use crate::Event;
28*bb4ee6a4SAndroid Build Coastguard Worker use crate::EventToken;
29*bb4ee6a4SAndroid Build Coastguard Worker use crate::EventType;
30*bb4ee6a4SAndroid Build Coastguard Worker use crate::RawDescriptor;
31*bb4ee6a4SAndroid Build Coastguard Worker use crate::TriggeredEvent;
32*bb4ee6a4SAndroid Build Coastguard Worker use crate::WaitContext;
33*bb4ee6a4SAndroid Build Coastguard Worker 
34*bb4ee6a4SAndroid Build Coastguard Worker // MAXIMUM_WAIT_OBJECTS = 64
35*bb4ee6a4SAndroid Build Coastguard Worker pub const MAXIMUM_WAIT_OBJECTS: usize = winapi::um::winnt::MAXIMUM_WAIT_OBJECTS as usize;
36*bb4ee6a4SAndroid Build Coastguard Worker 
37*bb4ee6a4SAndroid Build Coastguard Worker // TODO(145170451) rizhang: implement round robin if event size is greater than 64
38*bb4ee6a4SAndroid Build Coastguard Worker 
39*bb4ee6a4SAndroid Build Coastguard Worker pub trait WaitContextExt {
40*bb4ee6a4SAndroid Build Coastguard Worker     /// Removes all handles registered in the WaitContext.
clear(&self) -> Result<()>41*bb4ee6a4SAndroid Build Coastguard Worker     fn clear(&self) -> Result<()>;
42*bb4ee6a4SAndroid Build Coastguard Worker }
43*bb4ee6a4SAndroid Build Coastguard Worker 
44*bb4ee6a4SAndroid Build Coastguard Worker impl<T: EventToken> WaitContextExt for WaitContext<T> {
clear(&self) -> Result<()>45*bb4ee6a4SAndroid Build Coastguard Worker     fn clear(&self) -> Result<()> {
46*bb4ee6a4SAndroid Build Coastguard Worker         self.0.clear()
47*bb4ee6a4SAndroid Build Coastguard Worker     }
48*bb4ee6a4SAndroid Build Coastguard Worker }
49*bb4ee6a4SAndroid Build Coastguard Worker 
50*bb4ee6a4SAndroid Build Coastguard Worker struct RegisteredHandles<T: EventToken> {
51*bb4ee6a4SAndroid Build Coastguard Worker     triggers: HashMap<Descriptor, T>,
52*bb4ee6a4SAndroid Build Coastguard Worker     raw_handles: Vec<Descriptor>,
53*bb4ee6a4SAndroid Build Coastguard Worker }
54*bb4ee6a4SAndroid Build Coastguard Worker 
55*bb4ee6a4SAndroid Build Coastguard Worker pub struct EventContext<T: EventToken> {
56*bb4ee6a4SAndroid Build Coastguard Worker     registered_handles: Arc<Mutex<RegisteredHandles<T>>>,
57*bb4ee6a4SAndroid Build Coastguard Worker 
58*bb4ee6a4SAndroid Build Coastguard Worker     // An internally-used event to signify that the list of handles has been modified
59*bb4ee6a4SAndroid Build Coastguard Worker     // mid-wait. This is to solve for instances where Thread A has started waiting and
60*bb4ee6a4SAndroid Build Coastguard Worker     // Thread B adds an event trigger, which needs to notify Thread A a change has been
61*bb4ee6a4SAndroid Build Coastguard Worker     // made.
62*bb4ee6a4SAndroid Build Coastguard Worker     handles_modified_event: Event,
63*bb4ee6a4SAndroid Build Coastguard Worker }
64*bb4ee6a4SAndroid Build Coastguard Worker 
65*bb4ee6a4SAndroid Build Coastguard Worker impl<T: EventToken> EventContext<T> {
new() -> Result<EventContext<T>>66*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new() -> Result<EventContext<T>> {
67*bb4ee6a4SAndroid Build Coastguard Worker         let new = EventContext {
68*bb4ee6a4SAndroid Build Coastguard Worker             registered_handles: Arc::new(Mutex::new(RegisteredHandles {
69*bb4ee6a4SAndroid Build Coastguard Worker                 triggers: HashMap::new(),
70*bb4ee6a4SAndroid Build Coastguard Worker                 raw_handles: Vec::new(),
71*bb4ee6a4SAndroid Build Coastguard Worker             })),
72*bb4ee6a4SAndroid Build Coastguard Worker             handles_modified_event: Event::new().unwrap(),
73*bb4ee6a4SAndroid Build Coastguard Worker         };
74*bb4ee6a4SAndroid Build Coastguard Worker         // The handles-modified event will be everpresent on the raw_handles to be waited
75*bb4ee6a4SAndroid Build Coastguard Worker         // upon to ensure the wait stops and we update it any time the handles list is
76*bb4ee6a4SAndroid Build Coastguard Worker         // modified.
77*bb4ee6a4SAndroid Build Coastguard Worker         new.registered_handles
78*bb4ee6a4SAndroid Build Coastguard Worker             .lock()
79*bb4ee6a4SAndroid Build Coastguard Worker             .raw_handles
80*bb4ee6a4SAndroid Build Coastguard Worker             .push(Descriptor(new.handles_modified_event.as_raw_descriptor()));
81*bb4ee6a4SAndroid Build Coastguard Worker         Ok(new)
82*bb4ee6a4SAndroid Build Coastguard Worker     }
83*bb4ee6a4SAndroid Build Coastguard Worker 
84*bb4ee6a4SAndroid Build Coastguard Worker     /// Creates a new EventContext with the the associated triggers.
build_with(triggers: &[EventTrigger<T>]) -> Result<EventContext<T>>85*bb4ee6a4SAndroid Build Coastguard Worker     pub fn build_with(triggers: &[EventTrigger<T>]) -> Result<EventContext<T>> {
86*bb4ee6a4SAndroid Build Coastguard Worker         let ctx = EventContext::new()?;
87*bb4ee6a4SAndroid Build Coastguard Worker         ctx.add_many(triggers)?;
88*bb4ee6a4SAndroid Build Coastguard Worker         Ok(ctx)
89*bb4ee6a4SAndroid Build Coastguard Worker     }
90*bb4ee6a4SAndroid Build Coastguard Worker 
91*bb4ee6a4SAndroid Build Coastguard Worker     /// Adds a trigger to the EventContext.
add(&self, trigger: EventTrigger<T>) -> Result<()>92*bb4ee6a4SAndroid Build Coastguard Worker     pub fn add(&self, trigger: EventTrigger<T>) -> Result<()> {
93*bb4ee6a4SAndroid Build Coastguard Worker         self.add_for_event_impl(trigger, EventType::Read)
94*bb4ee6a4SAndroid Build Coastguard Worker     }
95*bb4ee6a4SAndroid Build Coastguard Worker 
96*bb4ee6a4SAndroid Build Coastguard Worker     /// Adds a trigger to the EventContext.
add_many(&self, triggers: &[EventTrigger<T>]) -> Result<()>97*bb4ee6a4SAndroid Build Coastguard Worker     pub fn add_many(&self, triggers: &[EventTrigger<T>]) -> Result<()> {
98*bb4ee6a4SAndroid Build Coastguard Worker         for trigger in triggers {
99*bb4ee6a4SAndroid Build Coastguard Worker             self.add(trigger.clone())?
100*bb4ee6a4SAndroid Build Coastguard Worker         }
101*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
102*bb4ee6a4SAndroid Build Coastguard Worker     }
103*bb4ee6a4SAndroid Build Coastguard Worker 
add_for_event( &self, descriptor: &dyn AsRawDescriptor, event_type: EventType, token: T, ) -> Result<()>104*bb4ee6a4SAndroid Build Coastguard Worker     pub fn add_for_event(
105*bb4ee6a4SAndroid Build Coastguard Worker         &self,
106*bb4ee6a4SAndroid Build Coastguard Worker         descriptor: &dyn AsRawDescriptor,
107*bb4ee6a4SAndroid Build Coastguard Worker         event_type: EventType,
108*bb4ee6a4SAndroid Build Coastguard Worker         token: T,
109*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
110*bb4ee6a4SAndroid Build Coastguard Worker         self.add_for_event_impl(EventTrigger::from(descriptor, token), event_type)
111*bb4ee6a4SAndroid Build Coastguard Worker     }
112*bb4ee6a4SAndroid Build Coastguard Worker 
add_for_event_impl(&self, trigger: EventTrigger<T>, _event_type: EventType) -> Result<()>113*bb4ee6a4SAndroid Build Coastguard Worker     fn add_for_event_impl(&self, trigger: EventTrigger<T>, _event_type: EventType) -> Result<()> {
114*bb4ee6a4SAndroid Build Coastguard Worker         let mut registered_handles_locked = self.registered_handles.lock();
115*bb4ee6a4SAndroid Build Coastguard Worker         if registered_handles_locked
116*bb4ee6a4SAndroid Build Coastguard Worker             .triggers
117*bb4ee6a4SAndroid Build Coastguard Worker             .contains_key(&Descriptor(trigger.event))
118*bb4ee6a4SAndroid Build Coastguard Worker         {
119*bb4ee6a4SAndroid Build Coastguard Worker             // If this handle is already added, silently succeed with a noop
120*bb4ee6a4SAndroid Build Coastguard Worker             return Ok(());
121*bb4ee6a4SAndroid Build Coastguard Worker         }
122*bb4ee6a4SAndroid Build Coastguard Worker         registered_handles_locked
123*bb4ee6a4SAndroid Build Coastguard Worker             .triggers
124*bb4ee6a4SAndroid Build Coastguard Worker             .insert(Descriptor(trigger.event), trigger.token);
125*bb4ee6a4SAndroid Build Coastguard Worker         registered_handles_locked
126*bb4ee6a4SAndroid Build Coastguard Worker             .raw_handles
127*bb4ee6a4SAndroid Build Coastguard Worker             .push(Descriptor(trigger.event));
128*bb4ee6a4SAndroid Build Coastguard Worker         // Windows doesn't support watching for specific types of events. Just treat this
129*bb4ee6a4SAndroid Build Coastguard Worker         // like a normal add and do nothing with event_type
130*bb4ee6a4SAndroid Build Coastguard Worker         self.handles_modified_event.signal()
131*bb4ee6a4SAndroid Build Coastguard Worker     }
132*bb4ee6a4SAndroid Build Coastguard Worker 
modify( &self, descriptor: &dyn AsRawDescriptor, _event_type: EventType, token: T, ) -> Result<()>133*bb4ee6a4SAndroid Build Coastguard Worker     pub fn modify(
134*bb4ee6a4SAndroid Build Coastguard Worker         &self,
135*bb4ee6a4SAndroid Build Coastguard Worker         descriptor: &dyn AsRawDescriptor,
136*bb4ee6a4SAndroid Build Coastguard Worker         _event_type: EventType,
137*bb4ee6a4SAndroid Build Coastguard Worker         token: T,
138*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
139*bb4ee6a4SAndroid Build Coastguard Worker         let trigger = EventTrigger::from(descriptor, token);
140*bb4ee6a4SAndroid Build Coastguard Worker 
141*bb4ee6a4SAndroid Build Coastguard Worker         let mut registered_handles_locked = self.registered_handles.lock();
142*bb4ee6a4SAndroid Build Coastguard Worker         if let std::collections::hash_map::Entry::Occupied(mut e) = registered_handles_locked
143*bb4ee6a4SAndroid Build Coastguard Worker             .triggers
144*bb4ee6a4SAndroid Build Coastguard Worker             .entry(Descriptor(trigger.event))
145*bb4ee6a4SAndroid Build Coastguard Worker         {
146*bb4ee6a4SAndroid Build Coastguard Worker             e.insert(trigger.token);
147*bb4ee6a4SAndroid Build Coastguard Worker         }
148*bb4ee6a4SAndroid Build Coastguard Worker         // Windows doesn't support watching for specific types of events. Ignore the event_type
149*bb4ee6a4SAndroid Build Coastguard Worker         // and just modify the token.
150*bb4ee6a4SAndroid Build Coastguard Worker         self.handles_modified_event.signal()
151*bb4ee6a4SAndroid Build Coastguard Worker     }
152*bb4ee6a4SAndroid Build Coastguard Worker 
delete(&self, event_handle: &dyn AsRawDescriptor) -> Result<()>153*bb4ee6a4SAndroid Build Coastguard Worker     pub fn delete(&self, event_handle: &dyn AsRawDescriptor) -> Result<()> {
154*bb4ee6a4SAndroid Build Coastguard Worker         let mut registered_handles_locked = self.registered_handles.lock();
155*bb4ee6a4SAndroid Build Coastguard Worker         let result = registered_handles_locked
156*bb4ee6a4SAndroid Build Coastguard Worker             .triggers
157*bb4ee6a4SAndroid Build Coastguard Worker             .remove(&Descriptor(event_handle.as_raw_descriptor()));
158*bb4ee6a4SAndroid Build Coastguard Worker         if result.is_none() {
159*bb4ee6a4SAndroid Build Coastguard Worker             // this handle was not registered in the first place. Silently succeed with a noop
160*bb4ee6a4SAndroid Build Coastguard Worker             return Ok(());
161*bb4ee6a4SAndroid Build Coastguard Worker         }
162*bb4ee6a4SAndroid Build Coastguard Worker         let index = registered_handles_locked
163*bb4ee6a4SAndroid Build Coastguard Worker             .raw_handles
164*bb4ee6a4SAndroid Build Coastguard Worker             .iter()
165*bb4ee6a4SAndroid Build Coastguard Worker             .position(|item| item == &Descriptor(event_handle.as_raw_descriptor()))
166*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
167*bb4ee6a4SAndroid Build Coastguard Worker         registered_handles_locked.raw_handles.remove(index);
168*bb4ee6a4SAndroid Build Coastguard Worker         self.handles_modified_event.signal()
169*bb4ee6a4SAndroid Build Coastguard Worker     }
170*bb4ee6a4SAndroid Build Coastguard Worker 
clear(&self) -> Result<()>171*bb4ee6a4SAndroid Build Coastguard Worker     pub fn clear(&self) -> Result<()> {
172*bb4ee6a4SAndroid Build Coastguard Worker         let mut registered_handles_locked = self.registered_handles.lock();
173*bb4ee6a4SAndroid Build Coastguard Worker         registered_handles_locked.triggers.clear();
174*bb4ee6a4SAndroid Build Coastguard Worker         registered_handles_locked.raw_handles.clear();
175*bb4ee6a4SAndroid Build Coastguard Worker 
176*bb4ee6a4SAndroid Build Coastguard Worker         registered_handles_locked
177*bb4ee6a4SAndroid Build Coastguard Worker             .raw_handles
178*bb4ee6a4SAndroid Build Coastguard Worker             .push(Descriptor(self.handles_modified_event.as_raw_descriptor()));
179*bb4ee6a4SAndroid Build Coastguard Worker         self.handles_modified_event.signal()
180*bb4ee6a4SAndroid Build Coastguard Worker     }
181*bb4ee6a4SAndroid Build Coastguard Worker 
182*bb4ee6a4SAndroid Build Coastguard Worker     /// Waits for one or more of the registered triggers to become signaled.
wait(&self) -> Result<SmallVec<[TriggeredEvent<T>; 16]>>183*bb4ee6a4SAndroid Build Coastguard Worker     pub fn wait(&self) -> Result<SmallVec<[TriggeredEvent<T>; 16]>> {
184*bb4ee6a4SAndroid Build Coastguard Worker         self.wait_timeout(Duration::new(i64::MAX as u64, 0))
185*bb4ee6a4SAndroid Build Coastguard Worker     }
186*bb4ee6a4SAndroid Build Coastguard Worker 
wait_timeout(&self, timeout: Duration) -> Result<SmallVec<[TriggeredEvent<T>; 16]>>187*bb4ee6a4SAndroid Build Coastguard Worker     pub fn wait_timeout(&self, timeout: Duration) -> Result<SmallVec<[TriggeredEvent<T>; 16]>> {
188*bb4ee6a4SAndroid Build Coastguard Worker         let raw_handles_list: Vec<RawHandle> = self
189*bb4ee6a4SAndroid Build Coastguard Worker             .registered_handles
190*bb4ee6a4SAndroid Build Coastguard Worker             .lock()
191*bb4ee6a4SAndroid Build Coastguard Worker             .raw_handles
192*bb4ee6a4SAndroid Build Coastguard Worker             .clone()
193*bb4ee6a4SAndroid Build Coastguard Worker             .into_iter()
194*bb4ee6a4SAndroid Build Coastguard Worker             .map(|handle| handle.0)
195*bb4ee6a4SAndroid Build Coastguard Worker             .collect();
196*bb4ee6a4SAndroid Build Coastguard Worker         if raw_handles_list.len() == 1 {
197*bb4ee6a4SAndroid Build Coastguard Worker             // Disallow calls with no handles to wait on. Do not include the handles_modified_event
198*bb4ee6a4SAndroid Build Coastguard Worker             // which always populates the list.
199*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::new(ERROR_INVALID_PARAMETER));
200*bb4ee6a4SAndroid Build Coastguard Worker         }
201*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY: raw handles array is expected to contain valid handles and the return value of
202*bb4ee6a4SAndroid Build Coastguard Worker         // the function is checked.
203*bb4ee6a4SAndroid Build Coastguard Worker         let result = unsafe {
204*bb4ee6a4SAndroid Build Coastguard Worker             WaitForMultipleObjects(
205*bb4ee6a4SAndroid Build Coastguard Worker                 raw_handles_list.len() as DWORD,
206*bb4ee6a4SAndroid Build Coastguard Worker                 raw_handles_list.as_ptr(),
207*bb4ee6a4SAndroid Build Coastguard Worker                 FALSE, // return when one event is signaled
208*bb4ee6a4SAndroid Build Coastguard Worker                 timeout.as_millis() as DWORD,
209*bb4ee6a4SAndroid Build Coastguard Worker             )
210*bb4ee6a4SAndroid Build Coastguard Worker         };
211*bb4ee6a4SAndroid Build Coastguard Worker         let handles_len = min(MAXIMUM_WAIT_OBJECTS, raw_handles_list.len());
212*bb4ee6a4SAndroid Build Coastguard Worker 
213*bb4ee6a4SAndroid Build Coastguard Worker         const MAXIMUM_WAIT_OBJECTS_U32: u32 = MAXIMUM_WAIT_OBJECTS as u32;
214*bb4ee6a4SAndroid Build Coastguard Worker         match result {
215*bb4ee6a4SAndroid Build Coastguard Worker             WAIT_OBJECT_0..=MAXIMUM_WAIT_OBJECTS_U32 => {
216*bb4ee6a4SAndroid Build Coastguard Worker                 let mut event_index = (result - WAIT_OBJECT_0) as usize;
217*bb4ee6a4SAndroid Build Coastguard Worker                 if event_index >= handles_len {
218*bb4ee6a4SAndroid Build Coastguard Worker                     // This is not a valid index and should return an error. This case should not be
219*bb4ee6a4SAndroid Build Coastguard Worker                     // possible and will likely not return a meaningful system
220*bb4ee6a4SAndroid Build Coastguard Worker                     // error code, but is still an invalid case.
221*bb4ee6a4SAndroid Build Coastguard Worker                     error!("Wait returned index out of range");
222*bb4ee6a4SAndroid Build Coastguard Worker                     return errno_result();
223*bb4ee6a4SAndroid Build Coastguard Worker                 }
224*bb4ee6a4SAndroid Build Coastguard Worker                 if event_index == 0 {
225*bb4ee6a4SAndroid Build Coastguard Worker                     // The handles list has been modified and triggered the wait, try again with the
226*bb4ee6a4SAndroid Build Coastguard Worker                     // updated handles list. Note it is possible the list was
227*bb4ee6a4SAndroid Build Coastguard Worker                     // modified again after the wait which will trigger the
228*bb4ee6a4SAndroid Build Coastguard Worker                     // handles_modified_event again, but that will only err towards the safe side
229*bb4ee6a4SAndroid Build Coastguard Worker                     // of recursing an extra time.
230*bb4ee6a4SAndroid Build Coastguard Worker                     let _ = self.handles_modified_event.wait();
231*bb4ee6a4SAndroid Build Coastguard Worker                     return self.wait_timeout(timeout);
232*bb4ee6a4SAndroid Build Coastguard Worker                 }
233*bb4ee6a4SAndroid Build Coastguard Worker 
234*bb4ee6a4SAndroid Build Coastguard Worker                 let mut events_to_return = SmallVec::<[TriggeredEvent<T>; 16]>::new();
235*bb4ee6a4SAndroid Build Coastguard Worker                 // Multiple events may be triggered at once, but WaitForMultipleObjects will only
236*bb4ee6a4SAndroid Build Coastguard Worker                 // return one. Once it returns, loop through the remaining triggers
237*bb4ee6a4SAndroid Build Coastguard Worker                 // checking each to ensure they haven't also been triggered.
238*bb4ee6a4SAndroid Build Coastguard Worker                 let mut handles_offset: usize = 0;
239*bb4ee6a4SAndroid Build Coastguard Worker                 loop {
240*bb4ee6a4SAndroid Build Coastguard Worker                     let event_to_return = raw_handles_list[event_index + handles_offset];
241*bb4ee6a4SAndroid Build Coastguard Worker                     events_to_return.push(TriggeredEvent {
242*bb4ee6a4SAndroid Build Coastguard Worker                         token: T::from_raw_token(
243*bb4ee6a4SAndroid Build Coastguard Worker                             self.registered_handles
244*bb4ee6a4SAndroid Build Coastguard Worker                                 .lock()
245*bb4ee6a4SAndroid Build Coastguard Worker                                 .triggers
246*bb4ee6a4SAndroid Build Coastguard Worker                                 .get(&Descriptor(event_to_return))
247*bb4ee6a4SAndroid Build Coastguard Worker                                 .unwrap()
248*bb4ee6a4SAndroid Build Coastguard Worker                                 .as_raw_token(),
249*bb4ee6a4SAndroid Build Coastguard Worker                         ),
250*bb4ee6a4SAndroid Build Coastguard Worker                         // In Windows, events aren't associated with read/writability, so for cross-
251*bb4ee6a4SAndroid Build Coastguard Worker                         // compatability, associate with both.
252*bb4ee6a4SAndroid Build Coastguard Worker                         is_readable: true,
253*bb4ee6a4SAndroid Build Coastguard Worker                         is_writable: true,
254*bb4ee6a4SAndroid Build Coastguard Worker                         is_hungup: false,
255*bb4ee6a4SAndroid Build Coastguard Worker                     });
256*bb4ee6a4SAndroid Build Coastguard Worker 
257*bb4ee6a4SAndroid Build Coastguard Worker                     handles_offset += event_index + 1;
258*bb4ee6a4SAndroid Build Coastguard Worker                     if handles_offset >= handles_len {
259*bb4ee6a4SAndroid Build Coastguard Worker                         break;
260*bb4ee6a4SAndroid Build Coastguard Worker                     }
261*bb4ee6a4SAndroid Build Coastguard Worker                     event_index = (
262*bb4ee6a4SAndroid Build Coastguard Worker                         // SAFETY: raw handles array is expected to contain valid handles and the
263*bb4ee6a4SAndroid Build Coastguard Worker                         // return value of the function is checked.
264*bb4ee6a4SAndroid Build Coastguard Worker                         unsafe {
265*bb4ee6a4SAndroid Build Coastguard Worker                             WaitForMultipleObjects(
266*bb4ee6a4SAndroid Build Coastguard Worker                                 (raw_handles_list.len() - handles_offset) as DWORD,
267*bb4ee6a4SAndroid Build Coastguard Worker                                 raw_handles_list[handles_offset..].as_ptr(),
268*bb4ee6a4SAndroid Build Coastguard Worker                                 FALSE, // return when one event is signaled
269*bb4ee6a4SAndroid Build Coastguard Worker                                 0,     /* instantaneous timeout */
270*bb4ee6a4SAndroid Build Coastguard Worker                             )
271*bb4ee6a4SAndroid Build Coastguard Worker                         } - WAIT_OBJECT_0
272*bb4ee6a4SAndroid Build Coastguard Worker                     ) as usize;
273*bb4ee6a4SAndroid Build Coastguard Worker 
274*bb4ee6a4SAndroid Build Coastguard Worker                     if event_index >= (handles_len - handles_offset) {
275*bb4ee6a4SAndroid Build Coastguard Worker                         // This indicates a failure condition, as return values greater than the
276*bb4ee6a4SAndroid Build Coastguard Worker                         // length of the provided array are reserved for
277*bb4ee6a4SAndroid Build Coastguard Worker                         // failures.
278*bb4ee6a4SAndroid Build Coastguard Worker                         break;
279*bb4ee6a4SAndroid Build Coastguard Worker                     }
280*bb4ee6a4SAndroid Build Coastguard Worker                 }
281*bb4ee6a4SAndroid Build Coastguard Worker 
282*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(events_to_return)
283*bb4ee6a4SAndroid Build Coastguard Worker             }
284*bb4ee6a4SAndroid Build Coastguard Worker             WAIT_TIMEOUT => Ok(Default::default()),
285*bb4ee6a4SAndroid Build Coastguard Worker             // Invalid cases. This is most likely an WAIT_FAILED, but anything not matched by the
286*bb4ee6a4SAndroid Build Coastguard Worker             // above is an error case.
287*bb4ee6a4SAndroid Build Coastguard Worker             _ => errno_result(),
288*bb4ee6a4SAndroid Build Coastguard Worker         }
289*bb4ee6a4SAndroid Build Coastguard Worker     }
290*bb4ee6a4SAndroid Build Coastguard Worker }
291*bb4ee6a4SAndroid Build Coastguard Worker 
292*bb4ee6a4SAndroid Build Coastguard Worker impl<T: EventToken> AsRawDescriptor for EventContext<T> {
as_raw_descriptor(&self) -> RawDescriptor293*bb4ee6a4SAndroid Build Coastguard Worker     fn as_raw_descriptor(&self) -> RawDescriptor {
294*bb4ee6a4SAndroid Build Coastguard Worker         self.handles_modified_event.as_raw_descriptor()
295*bb4ee6a4SAndroid Build Coastguard Worker     }
296*bb4ee6a4SAndroid Build Coastguard Worker }
297*bb4ee6a4SAndroid Build Coastguard Worker 
298*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
299*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
300*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
301*bb4ee6a4SAndroid Build Coastguard Worker 
302*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
303*bb4ee6a4SAndroid Build Coastguard Worker     #[should_panic]
error_on_empty_context_wait()304*bb4ee6a4SAndroid Build Coastguard Worker     fn error_on_empty_context_wait() {
305*bb4ee6a4SAndroid Build Coastguard Worker         let ctx: EventContext<u32> = EventContext::new().unwrap();
306*bb4ee6a4SAndroid Build Coastguard Worker         let dur = Duration::from_millis(10);
307*bb4ee6a4SAndroid Build Coastguard Worker         ctx.wait_timeout(dur).unwrap();
308*bb4ee6a4SAndroid Build Coastguard Worker     }
309*bb4ee6a4SAndroid Build Coastguard Worker }
310