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