1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2017 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::fs::File; 7*bb4ee6a4SAndroid Build Coastguard Worker use std::marker::PhantomData; 8*bb4ee6a4SAndroid Build Coastguard Worker use std::mem::MaybeUninit; 9*bb4ee6a4SAndroid Build Coastguard Worker use std::ptr::null_mut; 10*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration; 11*bb4ee6a4SAndroid Build Coastguard Worker 12*bb4ee6a4SAndroid Build Coastguard Worker use libc::c_int; 13*bb4ee6a4SAndroid Build Coastguard Worker use libc::epoll_create1; 14*bb4ee6a4SAndroid Build Coastguard Worker use libc::epoll_ctl; 15*bb4ee6a4SAndroid Build Coastguard Worker use libc::epoll_event; 16*bb4ee6a4SAndroid Build Coastguard Worker use libc::epoll_wait; 17*bb4ee6a4SAndroid Build Coastguard Worker use libc::ENOENT; 18*bb4ee6a4SAndroid Build Coastguard Worker use libc::EPOLLHUP; 19*bb4ee6a4SAndroid Build Coastguard Worker use libc::EPOLLIN; 20*bb4ee6a4SAndroid Build Coastguard Worker use libc::EPOLLOUT; 21*bb4ee6a4SAndroid Build Coastguard Worker use libc::EPOLLRDHUP; 22*bb4ee6a4SAndroid Build Coastguard Worker use libc::EPOLL_CLOEXEC; 23*bb4ee6a4SAndroid Build Coastguard Worker use libc::EPOLL_CTL_ADD; 24*bb4ee6a4SAndroid Build Coastguard Worker use libc::EPOLL_CTL_DEL; 25*bb4ee6a4SAndroid Build Coastguard Worker use libc::EPOLL_CTL_MOD; 26*bb4ee6a4SAndroid Build Coastguard Worker use smallvec::SmallVec; 27*bb4ee6a4SAndroid Build Coastguard Worker 28*bb4ee6a4SAndroid Build Coastguard Worker use super::errno_result; 29*bb4ee6a4SAndroid Build Coastguard Worker use super::Result; 30*bb4ee6a4SAndroid Build Coastguard Worker use crate::handle_eintr_errno; 31*bb4ee6a4SAndroid Build Coastguard Worker use crate::AsRawDescriptor; 32*bb4ee6a4SAndroid Build Coastguard Worker use crate::EventToken; 33*bb4ee6a4SAndroid Build Coastguard Worker use crate::EventType; 34*bb4ee6a4SAndroid Build Coastguard Worker use crate::FromRawDescriptor; 35*bb4ee6a4SAndroid Build Coastguard Worker use crate::RawDescriptor; 36*bb4ee6a4SAndroid Build Coastguard Worker use crate::TriggeredEvent; 37*bb4ee6a4SAndroid Build Coastguard Worker 38*bb4ee6a4SAndroid Build Coastguard Worker const EVENT_CONTEXT_MAX_EVENTS: usize = 16; 39*bb4ee6a4SAndroid Build Coastguard Worker 40*bb4ee6a4SAndroid Build Coastguard Worker impl From<EventType> for u32 { from(et: EventType) -> u3241*bb4ee6a4SAndroid Build Coastguard Worker fn from(et: EventType) -> u32 { 42*bb4ee6a4SAndroid Build Coastguard Worker let v = match et { 43*bb4ee6a4SAndroid Build Coastguard Worker EventType::None => 0, 44*bb4ee6a4SAndroid Build Coastguard Worker EventType::Read => EPOLLIN, 45*bb4ee6a4SAndroid Build Coastguard Worker EventType::Write => EPOLLOUT, 46*bb4ee6a4SAndroid Build Coastguard Worker EventType::ReadWrite => EPOLLIN | EPOLLOUT, 47*bb4ee6a4SAndroid Build Coastguard Worker }; 48*bb4ee6a4SAndroid Build Coastguard Worker v as u32 49*bb4ee6a4SAndroid Build Coastguard Worker } 50*bb4ee6a4SAndroid Build Coastguard Worker } 51*bb4ee6a4SAndroid Build Coastguard Worker 52*bb4ee6a4SAndroid Build Coastguard Worker /// Used to poll multiple objects that have file descriptors. 53*bb4ee6a4SAndroid Build Coastguard Worker /// 54*bb4ee6a4SAndroid Build Coastguard Worker /// See [`crate::WaitContext`] for an example that uses the cross-platform wrapper. 55*bb4ee6a4SAndroid Build Coastguard Worker pub struct EventContext<T> { 56*bb4ee6a4SAndroid Build Coastguard Worker epoll_ctx: File, 57*bb4ee6a4SAndroid Build Coastguard Worker // Needed to satisfy usage of T 58*bb4ee6a4SAndroid Build Coastguard Worker tokens: PhantomData<[T]>, 59*bb4ee6a4SAndroid Build Coastguard Worker } 60*bb4ee6a4SAndroid Build Coastguard Worker 61*bb4ee6a4SAndroid Build Coastguard Worker impl<T: EventToken> EventContext<T> { 62*bb4ee6a4SAndroid Build Coastguard Worker /// Creates a new `EventContext`. new() -> Result<EventContext<T>>63*bb4ee6a4SAndroid Build Coastguard Worker pub fn new() -> Result<EventContext<T>> { 64*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 65*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we check the return value. 66*bb4ee6a4SAndroid Build Coastguard Worker let epoll_fd = unsafe { epoll_create1(EPOLL_CLOEXEC) }; 67*bb4ee6a4SAndroid Build Coastguard Worker if epoll_fd < 0 { 68*bb4ee6a4SAndroid Build Coastguard Worker return errno_result(); 69*bb4ee6a4SAndroid Build Coastguard Worker } 70*bb4ee6a4SAndroid Build Coastguard Worker Ok(EventContext { 71*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 72*bb4ee6a4SAndroid Build Coastguard Worker // Safe because epoll_fd is valid. 73*bb4ee6a4SAndroid Build Coastguard Worker epoll_ctx: unsafe { File::from_raw_descriptor(epoll_fd) }, 74*bb4ee6a4SAndroid Build Coastguard Worker tokens: PhantomData, 75*bb4ee6a4SAndroid Build Coastguard Worker }) 76*bb4ee6a4SAndroid Build Coastguard Worker } 77*bb4ee6a4SAndroid Build Coastguard Worker 78*bb4ee6a4SAndroid Build Coastguard Worker /// Creates a new `EventContext` and adds the slice of `fd` and `token` tuples to the new 79*bb4ee6a4SAndroid Build Coastguard Worker /// context. 80*bb4ee6a4SAndroid Build Coastguard Worker /// 81*bb4ee6a4SAndroid Build Coastguard Worker /// This is equivalent to calling `new` followed by `add_many`. If there is an error, this will 82*bb4ee6a4SAndroid Build Coastguard Worker /// return the error instead of the new context. build_with(fd_tokens: &[(&dyn AsRawDescriptor, T)]) -> Result<EventContext<T>>83*bb4ee6a4SAndroid Build Coastguard Worker pub fn build_with(fd_tokens: &[(&dyn AsRawDescriptor, T)]) -> Result<EventContext<T>> { 84*bb4ee6a4SAndroid Build Coastguard Worker let ctx = EventContext::new()?; 85*bb4ee6a4SAndroid Build Coastguard Worker ctx.add_many(fd_tokens)?; 86*bb4ee6a4SAndroid Build Coastguard Worker Ok(ctx) 87*bb4ee6a4SAndroid Build Coastguard Worker } 88*bb4ee6a4SAndroid Build Coastguard Worker 89*bb4ee6a4SAndroid Build Coastguard Worker /// Adds the given slice of `fd` and `token` tuples to this context. 90*bb4ee6a4SAndroid Build Coastguard Worker /// 91*bb4ee6a4SAndroid Build Coastguard Worker /// This is equivalent to calling `add` with each `fd` and `token`. If there are any errors, 92*bb4ee6a4SAndroid Build Coastguard Worker /// this method will stop adding `fd`s and return the first error, leaving this context in a 93*bb4ee6a4SAndroid Build Coastguard Worker /// undefined state. add_many(&self, fd_tokens: &[(&dyn AsRawDescriptor, T)]) -> Result<()>94*bb4ee6a4SAndroid Build Coastguard Worker pub fn add_many(&self, fd_tokens: &[(&dyn AsRawDescriptor, T)]) -> Result<()> { 95*bb4ee6a4SAndroid Build Coastguard Worker for (fd, token) in fd_tokens { 96*bb4ee6a4SAndroid Build Coastguard Worker self.add(*fd, T::from_raw_token(token.as_raw_token()))?; 97*bb4ee6a4SAndroid Build Coastguard Worker } 98*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 99*bb4ee6a4SAndroid Build Coastguard Worker } 100*bb4ee6a4SAndroid Build Coastguard Worker 101*bb4ee6a4SAndroid Build Coastguard Worker /// Adds the given `fd` to this context and associates the given `token` with the `fd`'s 102*bb4ee6a4SAndroid Build Coastguard Worker /// readable events. 103*bb4ee6a4SAndroid Build Coastguard Worker /// 104*bb4ee6a4SAndroid Build Coastguard Worker /// A `fd` can only be added once and does not need to be kept open. If the `fd` is dropped and 105*bb4ee6a4SAndroid Build Coastguard Worker /// there were no duplicated file descriptors (i.e. adding the same descriptor with a different 106*bb4ee6a4SAndroid Build Coastguard Worker /// FD number) added to this context, events will not be reported by `wait` anymore. add(&self, fd: &dyn AsRawDescriptor, token: T) -> Result<()>107*bb4ee6a4SAndroid Build Coastguard Worker pub fn add(&self, fd: &dyn AsRawDescriptor, token: T) -> Result<()> { 108*bb4ee6a4SAndroid Build Coastguard Worker self.add_for_event(fd, EventType::Read, token) 109*bb4ee6a4SAndroid Build Coastguard Worker } 110*bb4ee6a4SAndroid Build Coastguard Worker 111*bb4ee6a4SAndroid Build Coastguard Worker /// Adds the given `descriptor` to this context, watching for the specified events and 112*bb4ee6a4SAndroid Build Coastguard Worker /// associates the given 'token' with those events. 113*bb4ee6a4SAndroid Build Coastguard Worker /// 114*bb4ee6a4SAndroid Build Coastguard Worker /// A `descriptor` can only be added once and does not need to be kept open. If the `descriptor` 115*bb4ee6a4SAndroid Build Coastguard Worker /// is dropped and there were no duplicated file descriptors (i.e. adding the same descriptor 116*bb4ee6a4SAndroid Build Coastguard Worker /// with a different FD number) added to this context, events will not be reported by `wait` 117*bb4ee6a4SAndroid Build Coastguard Worker /// anymore. add_for_event( &self, descriptor: &dyn AsRawDescriptor, event_type: EventType, token: T, ) -> Result<()>118*bb4ee6a4SAndroid Build Coastguard Worker pub fn add_for_event( 119*bb4ee6a4SAndroid Build Coastguard Worker &self, 120*bb4ee6a4SAndroid Build Coastguard Worker descriptor: &dyn AsRawDescriptor, 121*bb4ee6a4SAndroid Build Coastguard Worker event_type: EventType, 122*bb4ee6a4SAndroid Build Coastguard Worker token: T, 123*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 124*bb4ee6a4SAndroid Build Coastguard Worker let mut evt = epoll_event { 125*bb4ee6a4SAndroid Build Coastguard Worker events: event_type.into(), 126*bb4ee6a4SAndroid Build Coastguard Worker u64: token.as_raw_token(), 127*bb4ee6a4SAndroid Build Coastguard Worker }; 128*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 129*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we give a valid epoll FD and FD to watch, as well as a valid epoll_event 130*bb4ee6a4SAndroid Build Coastguard Worker // structure. Then we check the return value. 131*bb4ee6a4SAndroid Build Coastguard Worker let ret = unsafe { 132*bb4ee6a4SAndroid Build Coastguard Worker epoll_ctl( 133*bb4ee6a4SAndroid Build Coastguard Worker self.epoll_ctx.as_raw_descriptor(), 134*bb4ee6a4SAndroid Build Coastguard Worker EPOLL_CTL_ADD, 135*bb4ee6a4SAndroid Build Coastguard Worker descriptor.as_raw_descriptor(), 136*bb4ee6a4SAndroid Build Coastguard Worker &mut evt, 137*bb4ee6a4SAndroid Build Coastguard Worker ) 138*bb4ee6a4SAndroid Build Coastguard Worker }; 139*bb4ee6a4SAndroid Build Coastguard Worker if ret < 0 { 140*bb4ee6a4SAndroid Build Coastguard Worker return errno_result(); 141*bb4ee6a4SAndroid Build Coastguard Worker }; 142*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 143*bb4ee6a4SAndroid Build Coastguard Worker } 144*bb4ee6a4SAndroid Build Coastguard Worker 145*bb4ee6a4SAndroid Build Coastguard Worker /// If `fd` was previously added to this context, the watched events will be replaced with 146*bb4ee6a4SAndroid Build Coastguard Worker /// `event_type` and the token associated with it will be replaced with the given `token`. modify(&self, fd: &dyn AsRawDescriptor, event_type: EventType, token: T) -> Result<()>147*bb4ee6a4SAndroid Build Coastguard Worker pub fn modify(&self, fd: &dyn AsRawDescriptor, event_type: EventType, token: T) -> Result<()> { 148*bb4ee6a4SAndroid Build Coastguard Worker let mut evt = epoll_event { 149*bb4ee6a4SAndroid Build Coastguard Worker events: event_type.into(), 150*bb4ee6a4SAndroid Build Coastguard Worker u64: token.as_raw_token(), 151*bb4ee6a4SAndroid Build Coastguard Worker }; 152*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 153*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we give a valid epoll FD and FD to modify, as well as a valid epoll_event 154*bb4ee6a4SAndroid Build Coastguard Worker // structure. Then we check the return value. 155*bb4ee6a4SAndroid Build Coastguard Worker let ret = unsafe { 156*bb4ee6a4SAndroid Build Coastguard Worker epoll_ctl( 157*bb4ee6a4SAndroid Build Coastguard Worker self.epoll_ctx.as_raw_descriptor(), 158*bb4ee6a4SAndroid Build Coastguard Worker EPOLL_CTL_MOD, 159*bb4ee6a4SAndroid Build Coastguard Worker fd.as_raw_descriptor(), 160*bb4ee6a4SAndroid Build Coastguard Worker &mut evt, 161*bb4ee6a4SAndroid Build Coastguard Worker ) 162*bb4ee6a4SAndroid Build Coastguard Worker }; 163*bb4ee6a4SAndroid Build Coastguard Worker if ret < 0 { 164*bb4ee6a4SAndroid Build Coastguard Worker return errno_result(); 165*bb4ee6a4SAndroid Build Coastguard Worker }; 166*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 167*bb4ee6a4SAndroid Build Coastguard Worker } 168*bb4ee6a4SAndroid Build Coastguard Worker 169*bb4ee6a4SAndroid Build Coastguard Worker /// Deletes the given `fd` from this context. If the `fd` is not being polled by this context, 170*bb4ee6a4SAndroid Build Coastguard Worker /// the call is silently dropped without errors. 171*bb4ee6a4SAndroid Build Coastguard Worker /// 172*bb4ee6a4SAndroid Build Coastguard Worker /// If an `fd`'s token shows up in the list of hangup events, it should be removed using this 173*bb4ee6a4SAndroid Build Coastguard Worker /// method or by closing/dropping (if and only if the fd was never dup()'d/fork()'d) the `fd`. 174*bb4ee6a4SAndroid Build Coastguard Worker /// Failure to do so will cause the `wait` method to always return immediately, causing ~100% 175*bb4ee6a4SAndroid Build Coastguard Worker /// CPU load. delete(&self, fd: &dyn AsRawDescriptor) -> Result<()>176*bb4ee6a4SAndroid Build Coastguard Worker pub fn delete(&self, fd: &dyn AsRawDescriptor) -> Result<()> { 177*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 178*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we give a valid epoll FD and FD to stop watching. Then we check the return 179*bb4ee6a4SAndroid Build Coastguard Worker // value. 180*bb4ee6a4SAndroid Build Coastguard Worker let ret = unsafe { 181*bb4ee6a4SAndroid Build Coastguard Worker epoll_ctl( 182*bb4ee6a4SAndroid Build Coastguard Worker self.epoll_ctx.as_raw_descriptor(), 183*bb4ee6a4SAndroid Build Coastguard Worker EPOLL_CTL_DEL, 184*bb4ee6a4SAndroid Build Coastguard Worker fd.as_raw_descriptor(), 185*bb4ee6a4SAndroid Build Coastguard Worker null_mut(), 186*bb4ee6a4SAndroid Build Coastguard Worker ) 187*bb4ee6a4SAndroid Build Coastguard Worker }; 188*bb4ee6a4SAndroid Build Coastguard Worker // If epoll_ctl returns ENOENT it means the fd is not part of the current polling set so 189*bb4ee6a4SAndroid Build Coastguard Worker // there is nothing to delete. 190*bb4ee6a4SAndroid Build Coastguard Worker if ret < 0 && ret != ENOENT { 191*bb4ee6a4SAndroid Build Coastguard Worker return errno_result(); 192*bb4ee6a4SAndroid Build Coastguard Worker }; 193*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 194*bb4ee6a4SAndroid Build Coastguard Worker } 195*bb4ee6a4SAndroid Build Coastguard Worker 196*bb4ee6a4SAndroid Build Coastguard Worker /// Waits for any events to occur in FDs that were previously added to this context. 197*bb4ee6a4SAndroid Build Coastguard Worker /// 198*bb4ee6a4SAndroid Build Coastguard Worker /// The events are level-triggered, meaning that if any events are unhandled (i.e. not reading 199*bb4ee6a4SAndroid Build Coastguard Worker /// for readable events and not closing for hungup events), subsequent calls to `wait` will 200*bb4ee6a4SAndroid Build Coastguard Worker /// return immediately. The consequence of not handling an event perpetually while calling 201*bb4ee6a4SAndroid Build Coastguard Worker /// `wait` is that the callers loop will degenerated to busy loop polling, pinning a CPU to 202*bb4ee6a4SAndroid Build Coastguard Worker /// ~100% usage. wait(&self) -> Result<SmallVec<[TriggeredEvent<T>; 16]>>203*bb4ee6a4SAndroid Build Coastguard Worker pub fn wait(&self) -> Result<SmallVec<[TriggeredEvent<T>; 16]>> { 204*bb4ee6a4SAndroid Build Coastguard Worker self.wait_timeout(Duration::new(i64::MAX as u64, 0)) 205*bb4ee6a4SAndroid Build Coastguard Worker } 206*bb4ee6a4SAndroid Build Coastguard Worker 207*bb4ee6a4SAndroid Build Coastguard Worker /// Like `wait` except will only block for a maximum of the given `timeout`. 208*bb4ee6a4SAndroid Build Coastguard Worker /// 209*bb4ee6a4SAndroid Build Coastguard Worker /// This may return earlier than `timeout` with zero events if the duration indicated exceeds 210*bb4ee6a4SAndroid Build Coastguard Worker /// system limits. wait_timeout(&self, timeout: Duration) -> Result<SmallVec<[TriggeredEvent<T>; 16]>>211*bb4ee6a4SAndroid Build Coastguard Worker pub fn wait_timeout(&self, timeout: Duration) -> Result<SmallVec<[TriggeredEvent<T>; 16]>> { 212*bb4ee6a4SAndroid Build Coastguard Worker let mut epoll_events: [MaybeUninit<epoll_event>; EVENT_CONTEXT_MAX_EVENTS] = 213*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 214*bb4ee6a4SAndroid Build Coastguard Worker // `MaybeUnint<T>` has the same layout as plain `T` (`epoll_event` in our case). 215*bb4ee6a4SAndroid Build Coastguard Worker // We submit an uninitialized array to the `epoll_wait` system call, which returns how many 216*bb4ee6a4SAndroid Build Coastguard Worker // elements it initialized, and then we convert only the initialized `MaybeUnint` values 217*bb4ee6a4SAndroid Build Coastguard Worker // into `epoll_event` structures after the call. 218*bb4ee6a4SAndroid Build Coastguard Worker unsafe { MaybeUninit::uninit().assume_init() }; 219*bb4ee6a4SAndroid Build Coastguard Worker 220*bb4ee6a4SAndroid Build Coastguard Worker let timeout_millis = if timeout.as_secs() as i64 == i64::MAX { 221*bb4ee6a4SAndroid Build Coastguard Worker // We make the convenient assumption that 2^63 seconds is an effectively unbounded time 222*bb4ee6a4SAndroid Build Coastguard Worker // frame. This is meant to mesh with `wait` calling us with no timeout. 223*bb4ee6a4SAndroid Build Coastguard Worker -1 224*bb4ee6a4SAndroid Build Coastguard Worker } else { 225*bb4ee6a4SAndroid Build Coastguard Worker // In cases where we the number of milliseconds would overflow an i32, we substitute the 226*bb4ee6a4SAndroid Build Coastguard Worker // maximum timeout which is ~24.8 days. 227*bb4ee6a4SAndroid Build Coastguard Worker let millis = timeout 228*bb4ee6a4SAndroid Build Coastguard Worker .as_secs() 229*bb4ee6a4SAndroid Build Coastguard Worker .checked_mul(1_000) 230*bb4ee6a4SAndroid Build Coastguard Worker .and_then(|ms| ms.checked_add(u64::from(timeout.subsec_nanos()) / 1_000_000)) 231*bb4ee6a4SAndroid Build Coastguard Worker .unwrap_or(i32::MAX as u64); 232*bb4ee6a4SAndroid Build Coastguard Worker min(i32::MAX as u64, millis) as i32 233*bb4ee6a4SAndroid Build Coastguard Worker }; 234*bb4ee6a4SAndroid Build Coastguard Worker let ret = { 235*bb4ee6a4SAndroid Build Coastguard Worker let max_events = epoll_events.len() as c_int; 236*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 237*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we give an epoll context and a properly sized epoll_events array 238*bb4ee6a4SAndroid Build Coastguard Worker // pointer, which we trust the kernel to fill in properly. The `transmute` is safe, 239*bb4ee6a4SAndroid Build Coastguard Worker // since `MaybeUnint<T>` has the same layout as `T`, and the `epoll_wait` syscall will 240*bb4ee6a4SAndroid Build Coastguard Worker // initialize as many elements of the `epoll_events` array as it returns. 241*bb4ee6a4SAndroid Build Coastguard Worker unsafe { 242*bb4ee6a4SAndroid Build Coastguard Worker handle_eintr_errno!(epoll_wait( 243*bb4ee6a4SAndroid Build Coastguard Worker self.epoll_ctx.as_raw_descriptor(), 244*bb4ee6a4SAndroid Build Coastguard Worker std::mem::transmute(&mut epoll_events[0]), 245*bb4ee6a4SAndroid Build Coastguard Worker max_events, 246*bb4ee6a4SAndroid Build Coastguard Worker timeout_millis 247*bb4ee6a4SAndroid Build Coastguard Worker )) 248*bb4ee6a4SAndroid Build Coastguard Worker } 249*bb4ee6a4SAndroid Build Coastguard Worker }; 250*bb4ee6a4SAndroid Build Coastguard Worker if ret < 0 { 251*bb4ee6a4SAndroid Build Coastguard Worker return errno_result(); 252*bb4ee6a4SAndroid Build Coastguard Worker } 253*bb4ee6a4SAndroid Build Coastguard Worker let count = ret as usize; 254*bb4ee6a4SAndroid Build Coastguard Worker 255*bb4ee6a4SAndroid Build Coastguard Worker let events = epoll_events[0..count] 256*bb4ee6a4SAndroid Build Coastguard Worker .iter() 257*bb4ee6a4SAndroid Build Coastguard Worker .map(|e| { 258*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 259*bb4ee6a4SAndroid Build Coastguard Worker // Converting `MaybeUninit<epoll_event>` into `epoll_event` is safe here, since we 260*bb4ee6a4SAndroid Build Coastguard Worker // are only iterating over elements that the `epoll_wait` system call initialized. 261*bb4ee6a4SAndroid Build Coastguard Worker let e = unsafe { e.assume_init() }; 262*bb4ee6a4SAndroid Build Coastguard Worker TriggeredEvent { 263*bb4ee6a4SAndroid Build Coastguard Worker token: T::from_raw_token(e.u64), 264*bb4ee6a4SAndroid Build Coastguard Worker is_readable: e.events & (EPOLLIN as u32) != 0, 265*bb4ee6a4SAndroid Build Coastguard Worker is_writable: e.events & (EPOLLOUT as u32) != 0, 266*bb4ee6a4SAndroid Build Coastguard Worker is_hungup: e.events & ((EPOLLHUP | EPOLLRDHUP) as u32) != 0, 267*bb4ee6a4SAndroid Build Coastguard Worker } 268*bb4ee6a4SAndroid Build Coastguard Worker }) 269*bb4ee6a4SAndroid Build Coastguard Worker .collect(); 270*bb4ee6a4SAndroid Build Coastguard Worker Ok(events) 271*bb4ee6a4SAndroid Build Coastguard Worker } 272*bb4ee6a4SAndroid Build Coastguard Worker } 273*bb4ee6a4SAndroid Build Coastguard Worker 274*bb4ee6a4SAndroid Build Coastguard Worker impl<T: EventToken> AsRawDescriptor for EventContext<T> { as_raw_descriptor(&self) -> RawDescriptor275*bb4ee6a4SAndroid Build Coastguard Worker fn as_raw_descriptor(&self) -> RawDescriptor { 276*bb4ee6a4SAndroid Build Coastguard Worker self.epoll_ctx.as_raw_descriptor() 277*bb4ee6a4SAndroid Build Coastguard Worker } 278*bb4ee6a4SAndroid Build Coastguard Worker } 279*bb4ee6a4SAndroid Build Coastguard Worker 280*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)] 281*bb4ee6a4SAndroid Build Coastguard Worker mod tests { 282*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Instant; 283*bb4ee6a4SAndroid Build Coastguard Worker 284*bb4ee6a4SAndroid Build Coastguard Worker use base_event_token_derive::EventToken; 285*bb4ee6a4SAndroid Build Coastguard Worker 286*bb4ee6a4SAndroid Build Coastguard Worker use super::*; 287*bb4ee6a4SAndroid Build Coastguard Worker use crate::Event; 288*bb4ee6a4SAndroid Build Coastguard Worker 289*bb4ee6a4SAndroid Build Coastguard Worker #[test] event_context()290*bb4ee6a4SAndroid Build Coastguard Worker fn event_context() { 291*bb4ee6a4SAndroid Build Coastguard Worker let evt1 = Event::new().unwrap(); 292*bb4ee6a4SAndroid Build Coastguard Worker let evt2 = Event::new().unwrap(); 293*bb4ee6a4SAndroid Build Coastguard Worker evt1.signal().unwrap(); 294*bb4ee6a4SAndroid Build Coastguard Worker evt2.signal().unwrap(); 295*bb4ee6a4SAndroid Build Coastguard Worker let ctx: EventContext<u32> = EventContext::build_with(&[(&evt1, 1), (&evt2, 2)]).unwrap(); 296*bb4ee6a4SAndroid Build Coastguard Worker 297*bb4ee6a4SAndroid Build Coastguard Worker let mut evt_count = 0; 298*bb4ee6a4SAndroid Build Coastguard Worker while evt_count < 2 { 299*bb4ee6a4SAndroid Build Coastguard Worker for event in ctx.wait().unwrap().iter().filter(|e| e.is_readable) { 300*bb4ee6a4SAndroid Build Coastguard Worker evt_count += 1; 301*bb4ee6a4SAndroid Build Coastguard Worker match event.token { 302*bb4ee6a4SAndroid Build Coastguard Worker 1 => { 303*bb4ee6a4SAndroid Build Coastguard Worker evt1.wait().unwrap(); 304*bb4ee6a4SAndroid Build Coastguard Worker ctx.delete(&evt1).unwrap(); 305*bb4ee6a4SAndroid Build Coastguard Worker } 306*bb4ee6a4SAndroid Build Coastguard Worker 2 => { 307*bb4ee6a4SAndroid Build Coastguard Worker evt2.wait().unwrap(); 308*bb4ee6a4SAndroid Build Coastguard Worker ctx.delete(&evt2).unwrap(); 309*bb4ee6a4SAndroid Build Coastguard Worker } 310*bb4ee6a4SAndroid Build Coastguard Worker _ => panic!("unexpected token"), 311*bb4ee6a4SAndroid Build Coastguard Worker }; 312*bb4ee6a4SAndroid Build Coastguard Worker } 313*bb4ee6a4SAndroid Build Coastguard Worker } 314*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(evt_count, 2); 315*bb4ee6a4SAndroid Build Coastguard Worker } 316*bb4ee6a4SAndroid Build Coastguard Worker 317*bb4ee6a4SAndroid Build Coastguard Worker #[test] event_context_overflow()318*bb4ee6a4SAndroid Build Coastguard Worker fn event_context_overflow() { 319*bb4ee6a4SAndroid Build Coastguard Worker const EVT_COUNT: usize = EVENT_CONTEXT_MAX_EVENTS * 2 + 1; 320*bb4ee6a4SAndroid Build Coastguard Worker let ctx: EventContext<usize> = EventContext::new().unwrap(); 321*bb4ee6a4SAndroid Build Coastguard Worker let mut evts = Vec::with_capacity(EVT_COUNT); 322*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..EVT_COUNT { 323*bb4ee6a4SAndroid Build Coastguard Worker let evt = Event::new().unwrap(); 324*bb4ee6a4SAndroid Build Coastguard Worker evt.signal().unwrap(); 325*bb4ee6a4SAndroid Build Coastguard Worker ctx.add(&evt, i).unwrap(); 326*bb4ee6a4SAndroid Build Coastguard Worker evts.push(evt); 327*bb4ee6a4SAndroid Build Coastguard Worker } 328*bb4ee6a4SAndroid Build Coastguard Worker let mut evt_count = 0; 329*bb4ee6a4SAndroid Build Coastguard Worker while evt_count < EVT_COUNT { 330*bb4ee6a4SAndroid Build Coastguard Worker for event in ctx.wait().unwrap().iter().filter(|e| e.is_readable) { 331*bb4ee6a4SAndroid Build Coastguard Worker evts[event.token].wait().unwrap(); 332*bb4ee6a4SAndroid Build Coastguard Worker evt_count += 1; 333*bb4ee6a4SAndroid Build Coastguard Worker } 334*bb4ee6a4SAndroid Build Coastguard Worker } 335*bb4ee6a4SAndroid Build Coastguard Worker } 336*bb4ee6a4SAndroid Build Coastguard Worker 337*bb4ee6a4SAndroid Build Coastguard Worker #[test] event_context_timeout()338*bb4ee6a4SAndroid Build Coastguard Worker fn event_context_timeout() { 339*bb4ee6a4SAndroid Build Coastguard Worker let ctx: EventContext<u32> = EventContext::new().unwrap(); 340*bb4ee6a4SAndroid Build Coastguard Worker let dur = Duration::from_millis(10); 341*bb4ee6a4SAndroid Build Coastguard Worker let start_inst = Instant::now(); 342*bb4ee6a4SAndroid Build Coastguard Worker ctx.wait_timeout(dur).unwrap(); 343*bb4ee6a4SAndroid Build Coastguard Worker assert!(start_inst.elapsed() >= dur); 344*bb4ee6a4SAndroid Build Coastguard Worker } 345*bb4ee6a4SAndroid Build Coastguard Worker 346*bb4ee6a4SAndroid Build Coastguard Worker #[test] 347*bb4ee6a4SAndroid Build Coastguard Worker #[allow(dead_code)] event_token_derive()348*bb4ee6a4SAndroid Build Coastguard Worker fn event_token_derive() { 349*bb4ee6a4SAndroid Build Coastguard Worker #[derive(EventToken)] 350*bb4ee6a4SAndroid Build Coastguard Worker enum EmptyToken {} 351*bb4ee6a4SAndroid Build Coastguard Worker 352*bb4ee6a4SAndroid Build Coastguard Worker #[derive(PartialEq, Debug, EventToken)] 353*bb4ee6a4SAndroid Build Coastguard Worker enum Token { 354*bb4ee6a4SAndroid Build Coastguard Worker Alpha, 355*bb4ee6a4SAndroid Build Coastguard Worker Beta, 356*bb4ee6a4SAndroid Build Coastguard Worker // comments 357*bb4ee6a4SAndroid Build Coastguard Worker Gamma(u32), 358*bb4ee6a4SAndroid Build Coastguard Worker Delta { index: usize }, 359*bb4ee6a4SAndroid Build Coastguard Worker Omega, 360*bb4ee6a4SAndroid Build Coastguard Worker } 361*bb4ee6a4SAndroid Build Coastguard Worker 362*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 363*bb4ee6a4SAndroid Build Coastguard Worker Token::from_raw_token(Token::Alpha.as_raw_token()), 364*bb4ee6a4SAndroid Build Coastguard Worker Token::Alpha 365*bb4ee6a4SAndroid Build Coastguard Worker ); 366*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 367*bb4ee6a4SAndroid Build Coastguard Worker Token::from_raw_token(Token::Beta.as_raw_token()), 368*bb4ee6a4SAndroid Build Coastguard Worker Token::Beta 369*bb4ee6a4SAndroid Build Coastguard Worker ); 370*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 371*bb4ee6a4SAndroid Build Coastguard Worker Token::from_raw_token(Token::Gamma(55).as_raw_token()), 372*bb4ee6a4SAndroid Build Coastguard Worker Token::Gamma(55) 373*bb4ee6a4SAndroid Build Coastguard Worker ); 374*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 375*bb4ee6a4SAndroid Build Coastguard Worker Token::from_raw_token(Token::Delta { index: 100 }.as_raw_token()), 376*bb4ee6a4SAndroid Build Coastguard Worker Token::Delta { index: 100 } 377*bb4ee6a4SAndroid Build Coastguard Worker ); 378*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 379*bb4ee6a4SAndroid Build Coastguard Worker Token::from_raw_token(Token::Omega.as_raw_token()), 380*bb4ee6a4SAndroid Build Coastguard Worker Token::Omega 381*bb4ee6a4SAndroid Build Coastguard Worker ); 382*bb4ee6a4SAndroid Build Coastguard Worker } 383*bb4ee6a4SAndroid Build Coastguard Worker } 384