xref: /aosp_15_r20/external/crosvm/base/src/sys/linux/poll.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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