1 //! Linux `epoll` support.
2 //!
3 //! # Examples
4 //!
5 //! ```no_run
6 //! # #[cfg(feature = "net")]
7 //! # fn main() -> std::io::Result<()> {
8 //! use rustix::event::epoll;
9 //! use rustix::fd::AsFd;
10 //! use rustix::io::{ioctl_fionbio, read, write};
11 //! use rustix::net::{
12 //!     accept, bind_v4, listen, socket, AddressFamily, Ipv4Addr, SocketAddrV4, SocketType,
13 //! };
14 //! use std::collections::HashMap;
15 //! use std::os::unix::io::AsRawFd;
16 //!
17 //! // Create a socket and listen on it.
18 //! let listen_sock = socket(AddressFamily::INET, SocketType::STREAM, None)?;
19 //! bind_v4(&listen_sock, &SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0))?;
20 //! listen(&listen_sock, 1)?;
21 //!
22 //! // Create an epoll object. Using `Owning` here means the epoll object will
23 //! // take ownership of the file descriptors registered with it.
24 //! let epoll = epoll::create(epoll::CreateFlags::CLOEXEC)?;
25 //!
26 //! // Register the socket with the epoll object.
27 //! epoll::add(
28 //!     &epoll,
29 //!     &listen_sock,
30 //!     epoll::EventData::new_u64(1),
31 //!     epoll::EventFlags::IN,
32 //! )?;
33 //!
34 //! // Keep track of the sockets we've opened.
35 //! let mut next_id = epoll::EventData::new_u64(2);
36 //! let mut sockets = HashMap::new();
37 //!
38 //! // Process events.
39 //! let mut event_list = epoll::EventVec::with_capacity(4);
40 //! loop {
41 //!     epoll::wait(&epoll, &mut event_list, -1)?;
42 //!     for event in &event_list {
43 //!         let target = event.data;
44 //!         if target.u64() == 1 {
45 //!             // Accept a new connection, set it to non-blocking, and
46 //!             // register to be notified when it's ready to write to.
47 //!             let conn_sock = accept(&listen_sock)?;
48 //!             ioctl_fionbio(&conn_sock, true)?;
49 //!             epoll::add(
50 //!                 &epoll,
51 //!                 &conn_sock,
52 //!                 next_id,
53 //!                 epoll::EventFlags::OUT | epoll::EventFlags::ET,
54 //!             )?;
55 //!
56 //!             // Keep track of the socket.
57 //!             sockets.insert(next_id, conn_sock);
58 //!             next_id = epoll::EventData::new_u64(next_id.u64() + 1);
59 //!         } else {
60 //!             // Write a message to the stream and then unregister it.
61 //!             let target = sockets.remove(&target).unwrap();
62 //!             write(&target, b"hello\n")?;
63 //!             let _ = epoll::delete(&epoll, &target)?;
64 //!         }
65 //!     }
66 //! }
67 //! # }
68 //! # #[cfg(not(feature = "net"))]
69 //! # fn main() {}
70 //! ```
71 
72 #![allow(unsafe_code)]
73 
74 use crate::backend::c;
75 use crate::backend::event::syscalls;
76 use crate::fd::{AsFd, AsRawFd, OwnedFd};
77 use crate::io;
78 #[cfg(feature = "alloc")]
79 use alloc::vec::Vec;
80 use bitflags::bitflags;
81 use core::ffi::c_void;
82 use core::hash::{Hash, Hasher};
83 use core::slice;
84 
85 bitflags! {
86     /// `EPOLL_*` for use with [`new`].
87     #[repr(transparent)]
88     #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
89     pub struct CreateFlags: c::c_uint {
90         /// `EPOLL_CLOEXEC`
91         const CLOEXEC = linux_raw_sys::general::EPOLL_CLOEXEC;
92 
93         /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
94         const _ = !0;
95     }
96 }
97 
98 bitflags! {
99     /// `EPOLL*` for use with [`add`].
100     #[repr(transparent)]
101     #[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Debug)]
102     pub struct EventFlags: u32 {
103         /// `EPOLLIN`
104         const IN = linux_raw_sys::general::EPOLLIN as u32;
105 
106         /// `EPOLLOUT`
107         const OUT = linux_raw_sys::general::EPOLLOUT as u32;
108 
109         /// `EPOLLPRI`
110         const PRI = linux_raw_sys::general::EPOLLPRI as u32;
111 
112         /// `EPOLLERR`
113         const ERR = linux_raw_sys::general::EPOLLERR as u32;
114 
115         /// `EPOLLHUP`
116         const HUP = linux_raw_sys::general::EPOLLHUP as u32;
117 
118         /// `EPOLLRDNORM`
119         const RDNORM = linux_raw_sys::general::EPOLLRDNORM as u32;
120 
121         /// `EPOLLRDBAND`
122         const RDBAND = linux_raw_sys::general::EPOLLRDBAND as u32;
123 
124         /// `EPOLLWRNORM`
125         const WRNORM = linux_raw_sys::general::EPOLLWRNORM as u32;
126 
127         /// `EPOLLWRBAND`
128         const WRBAND = linux_raw_sys::general::EPOLLWRBAND as u32;
129 
130         /// `EPOLLMSG`
131         const MSG = linux_raw_sys::general::EPOLLMSG as u32;
132 
133         /// `EPOLLRDHUP`
134         const RDHUP = linux_raw_sys::general::EPOLLRDHUP as u32;
135 
136         /// `EPOLLET`
137         const ET = linux_raw_sys::general::EPOLLET as u32;
138 
139         /// `EPOLLONESHOT`
140         const ONESHOT = linux_raw_sys::general::EPOLLONESHOT as u32;
141 
142         /// `EPOLLWAKEUP`
143         const WAKEUP = linux_raw_sys::general::EPOLLWAKEUP as u32;
144 
145         /// `EPOLLEXCLUSIVE`
146         const EXCLUSIVE = linux_raw_sys::general::EPOLLEXCLUSIVE as u32;
147 
148         /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
149         const _ = !0;
150     }
151 }
152 
153 /// `epoll_create1(flags)`—Creates a new epoll object.
154 ///
155 /// Use the [`CreateFlags::CLOEXEC`] flag to prevent the resulting file
156 /// descriptor from being implicitly passed across `exec` boundaries.
157 #[inline]
158 #[doc(alias = "epoll_create1")]
create(flags: CreateFlags) -> io::Result<OwnedFd>159 pub fn create(flags: CreateFlags) -> io::Result<OwnedFd> {
160     syscalls::epoll_create(flags)
161 }
162 
163 /// `epoll_ctl(self, EPOLL_CTL_ADD, data, event)`—Adds an element to an epoll
164 /// object.
165 ///
166 /// This registers interest in any of the events set in `events` occurring on
167 /// the file descriptor associated with `data`.
168 ///
169 /// If [`delete`] is not called on the I/O source passed into this function
170 /// before the I/O source is `close`d, then the `epoll` will act as if the I/O
171 /// source is still registered with it. This can lead to spurious events being
172 /// returned from [`wait`]. If a file descriptor is an
173 /// `Arc<dyn SystemResource>`, then `epoll` can be thought to maintain a
174 /// `Weak<dyn SystemResource>` to the file descriptor.
175 #[doc(alias = "epoll_ctl")]
176 #[inline]
add( epoll: impl AsFd, source: impl AsFd, data: EventData, event_flags: EventFlags, ) -> io::Result<()>177 pub fn add(
178     epoll: impl AsFd,
179     source: impl AsFd,
180     data: EventData,
181     event_flags: EventFlags,
182 ) -> io::Result<()> {
183     // SAFETY: We're calling `epoll_ctl` via FFI and we know how it
184     // behaves.
185     unsafe {
186         syscalls::epoll_add(
187             epoll.as_fd(),
188             source.as_fd().as_raw_fd(),
189             &Event {
190                 flags: event_flags,
191                 data,
192             },
193         )
194     }
195 }
196 
197 /// `epoll_ctl(self, EPOLL_CTL_MOD, target, event)`—Modifies an element in a
198 /// given epoll object.
199 ///
200 /// This sets the events of interest with `target` to `events`.
201 #[doc(alias = "epoll_ctl")]
202 #[inline]
modify( epoll: impl AsFd, source: impl AsFd, data: EventData, event_flags: EventFlags, ) -> io::Result<()>203 pub fn modify(
204     epoll: impl AsFd,
205     source: impl AsFd,
206     data: EventData,
207     event_flags: EventFlags,
208 ) -> io::Result<()> {
209     // SAFETY: We're calling `epoll_ctl` via FFI and we know how it
210     // behaves.
211     unsafe {
212         let raw_fd = source.as_fd().as_raw_fd();
213         syscalls::epoll_mod(
214             epoll.as_fd(),
215             raw_fd,
216             &Event {
217                 flags: event_flags,
218                 data,
219             },
220         )
221     }
222 }
223 
224 /// `epoll_ctl(self, EPOLL_CTL_DEL, target, NULL)`—Removes an element in a
225 /// given epoll object.
226 #[doc(alias = "epoll_ctl")]
227 #[inline]
delete(epoll: impl AsFd, source: impl AsFd) -> io::Result<()>228 pub fn delete(epoll: impl AsFd, source: impl AsFd) -> io::Result<()> {
229     // SAFETY: We're calling `epoll_ctl` via FFI and we know how it
230     // behaves.
231     unsafe {
232         let raw_fd = source.as_fd().as_raw_fd();
233         syscalls::epoll_del(epoll.as_fd(), raw_fd)
234     }
235 }
236 
237 /// `epoll_wait(self, events, timeout)`—Waits for registered events of
238 /// interest.
239 ///
240 /// For each event of interest, an element is written to `events`. On
241 /// success, this returns the number of written elements.
242 #[cfg(feature = "alloc")]
243 #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
244 #[inline]
wait(epoll: impl AsFd, event_list: &mut EventVec, timeout: c::c_int) -> io::Result<()>245 pub fn wait(epoll: impl AsFd, event_list: &mut EventVec, timeout: c::c_int) -> io::Result<()> {
246     // SAFETY: We're calling `epoll_wait` via FFI and we know how it
247     // behaves.
248     unsafe {
249         event_list.events.set_len(0);
250         let nfds = syscalls::epoll_wait(
251             epoll.as_fd(),
252             event_list.events[..].as_mut_ptr().cast(),
253             event_list.events.capacity(),
254             timeout,
255         )?;
256         event_list.events.set_len(nfds);
257     }
258 
259     Ok(())
260 }
261 
262 /// An iterator over the `Event`s in an `EventVec`.
263 pub struct Iter<'a> {
264     /// Use `Copied` to copy the struct, since `Event` is `packed` on some
265     /// platforms, and it's common for users to directly destructure it, which
266     /// would lead to errors about forming references to packed fields.
267     iter: core::iter::Copied<slice::Iter<'a, Event>>,
268 }
269 
270 impl<'a> Iterator for Iter<'a> {
271     type Item = Event;
272 
273     #[inline]
next(&mut self) -> Option<Self::Item>274     fn next(&mut self) -> Option<Self::Item> {
275         self.iter.next()
276     }
277 }
278 
279 /// A record of an event that occurred.
280 #[repr(C)]
281 #[cfg_attr(target_arch = "x86_64", repr(packed))]
282 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
283 pub struct Event {
284     /// Which specific event(s) occurred.
285     pub flags: EventFlags,
286     /// User data.
287     pub data: EventData,
288 }
289 
290 /// Data associated with an [`Event`]. This can either be a 64-bit integer
291 /// value or a pointer which preserves pointer provenance.
292 #[repr(C)]
293 #[derive(Copy, Clone)]
294 pub union EventData {
295     /// A 64-bit integer value.
296     as_u64: u64,
297 
298     /// A `*mut c_void` which preserves pointer provenance, extended to be
299     /// 64-bit so that if we read the value as a `u64` union field, we don't
300     /// get uninitialized memory.
301     sixty_four_bit_pointer: SixtyFourBitPointer,
302 }
303 
304 impl EventData {
305     /// Construct a new value containing a `u64`.
306     #[inline]
new_u64(value: u64) -> Self307     pub const fn new_u64(value: u64) -> Self {
308         Self { as_u64: value }
309     }
310 
311     /// Construct a new value containing a `*mut c_void`.
312     #[inline]
new_ptr(value: *mut c_void) -> Self313     pub const fn new_ptr(value: *mut c_void) -> Self {
314         Self {
315             sixty_four_bit_pointer: SixtyFourBitPointer {
316                 pointer: value,
317                 #[cfg(target_pointer_width = "32")]
318                 _padding: 0,
319             },
320         }
321     }
322 
323     /// Return the value as a `u64`.
324     ///
325     /// If the stored value was a pointer, the pointer is zero-extended to a
326     /// `u64`.
327     #[inline]
u64(self) -> u64328     pub fn u64(self) -> u64 {
329         unsafe { self.as_u64 }
330     }
331 
332     /// Return the value as a `*mut c_void`.
333     ///
334     /// If the stored value was a `u64`, the least-significant bits of the
335     /// `u64` are returned as a pointer value.
336     #[inline]
ptr(self) -> *mut c_void337     pub fn ptr(self) -> *mut c_void {
338         unsafe { self.sixty_four_bit_pointer.pointer }
339     }
340 }
341 
342 impl PartialEq for EventData {
343     #[inline]
eq(&self, other: &Self) -> bool344     fn eq(&self, other: &Self) -> bool {
345         self.u64() == other.u64()
346     }
347 }
348 
349 impl Eq for EventData {}
350 
351 impl Hash for EventData {
352     #[inline]
hash<H: Hasher>(&self, state: &mut H)353     fn hash<H: Hasher>(&self, state: &mut H) {
354         self.u64().hash(state)
355     }
356 }
357 
358 #[repr(C)]
359 #[derive(Copy, Clone)]
360 struct SixtyFourBitPointer {
361     #[cfg(target_endian = "big")]
362     #[cfg(target_pointer_width = "32")]
363     _padding: u32,
364 
365     pointer: *mut c_void,
366 
367     #[cfg(target_endian = "little")]
368     #[cfg(target_pointer_width = "32")]
369     _padding: u32,
370 }
371 
372 /// A vector of `Event`s, plus context for interpreting them.
373 #[cfg(feature = "alloc")]
374 pub struct EventVec {
375     events: Vec<Event>,
376 }
377 
378 #[cfg(feature = "alloc")]
379 impl EventVec {
380     /// Constructs an `EventVec` from raw pointer, length, and capacity.
381     ///
382     /// # Safety
383     ///
384     /// This function calls [`Vec::from_raw_parts`] with its arguments.
385     ///
386     /// [`Vec::from_raw_parts`]: https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.from_raw_parts
387     #[inline]
from_raw_parts(ptr: *mut Event, len: usize, capacity: usize) -> Self388     pub unsafe fn from_raw_parts(ptr: *mut Event, len: usize, capacity: usize) -> Self {
389         Self {
390             events: Vec::from_raw_parts(ptr, len, capacity),
391         }
392     }
393 
394     /// Constructs an `EventVec` with memory for `capacity` `Event`s.
395     #[inline]
with_capacity(capacity: usize) -> Self396     pub fn with_capacity(capacity: usize) -> Self {
397         Self {
398             events: Vec::with_capacity(capacity),
399         }
400     }
401 
402     /// Returns the current `Event` capacity of this `EventVec`.
403     #[inline]
capacity(&self) -> usize404     pub fn capacity(&self) -> usize {
405         self.events.capacity()
406     }
407 
408     /// Reserves enough memory for at least `additional` more `Event`s.
409     #[inline]
reserve(&mut self, additional: usize)410     pub fn reserve(&mut self, additional: usize) {
411         self.events.reserve(additional);
412     }
413 
414     /// Reserves enough memory for exactly `additional` more `Event`s.
415     #[inline]
reserve_exact(&mut self, additional: usize)416     pub fn reserve_exact(&mut self, additional: usize) {
417         self.events.reserve_exact(additional);
418     }
419 
420     /// Clears all the `Events` out of this `EventVec`.
421     #[inline]
clear(&mut self)422     pub fn clear(&mut self) {
423         self.events.clear();
424     }
425 
426     /// Shrinks the capacity of this `EventVec` as much as possible.
427     #[inline]
shrink_to_fit(&mut self)428     pub fn shrink_to_fit(&mut self) {
429         self.events.shrink_to_fit();
430     }
431 
432     /// Returns an iterator over the `Event`s in this `EventVec`.
433     #[inline]
iter(&self) -> Iter<'_>434     pub fn iter(&self) -> Iter<'_> {
435         Iter {
436             iter: self.events.iter().copied(),
437         }
438     }
439 
440     /// Returns the number of `Event`s logically contained in this `EventVec`.
441     #[inline]
len(&mut self) -> usize442     pub fn len(&mut self) -> usize {
443         self.events.len()
444     }
445 
446     /// Tests whether this `EventVec` is logically empty.
447     #[inline]
is_empty(&mut self) -> bool448     pub fn is_empty(&mut self) -> bool {
449         self.events.is_empty()
450     }
451 }
452 
453 #[cfg(feature = "alloc")]
454 impl<'a> IntoIterator for &'a EventVec {
455     type IntoIter = Iter<'a>;
456     type Item = Event;
457 
458     #[inline]
into_iter(self) -> Self::IntoIter459     fn into_iter(self) -> Self::IntoIter {
460         self.iter()
461     }
462 }
463 
464 #[test]
test_epoll_layouts()465 fn test_epoll_layouts() {
466     check_renamed_type!(Event, epoll_event);
467     check_renamed_type!(Event, epoll_event);
468     check_renamed_struct_renamed_field!(Event, epoll_event, flags, events);
469     check_renamed_struct_renamed_field!(Event, epoll_event, data, data);
470 }
471