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
74use crate::backend::c;
75use crate::backend::event::syscalls;
76use crate::fd::{AsFd, AsRawFd, OwnedFd};
77use crate::io;
78#[cfg(feature = "alloc")]
79use alloc::vec::Vec;
80use bitflags::bitflags;
81use core::ffi::c_void;
82use core::hash::{Hash, Hasher};
83use core::slice;
84
85bitflags! {
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
98bitflags! {
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")]
159pub 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]
177pub 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 epfd: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]
203pub 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: i32 = source.as_fd().as_raw_fd();
213 syscalls::epoll_mod(
214 epfd: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]
228pub 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: i32 = source.as_fd().as_raw_fd();
233 syscalls::epoll_del(epfd: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]
245pub 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(new_len:0);
250 let nfds: usize = syscalls::epoll_wait(
251 epfd:epoll.as_fd(),
252 events:event_list.events[..].as_mut_ptr().cast(),
253 num_events:event_list.events.capacity(),
254 timeout,
255 )?;
256 event_list.events.set_len(new_len:nfds);
257 }
258
259 Ok(())
260}
261
262/// An iterator over the `Event`s in an `EventVec`.
263pub 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
270impl<'a> Iterator for Iter<'a> {
271 type Item = Event;
272
273 #[inline]
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)]
283pub 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)]
294pub 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
304impl EventData {
305 /// Construct a new value containing a `u64`.
306 #[inline]
307 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]
313 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]
328 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]
337 pub fn ptr(self) -> *mut c_void {
338 unsafe { self.sixty_four_bit_pointer.pointer }
339 }
340}
341
342impl PartialEq for EventData {
343 #[inline]
344 fn eq(&self, other: &Self) -> bool {
345 self.u64() == other.u64()
346 }
347}
348
349impl Eq for EventData {}
350
351impl Hash for EventData {
352 #[inline]
353 fn hash<H: Hasher>(&self, state: &mut H) {
354 self.u64().hash(state)
355 }
356}
357
358#[repr(C)]
359#[derive(Copy, Clone)]
360struct 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")]
374pub struct EventVec {
375 events: Vec<Event>,
376}
377
378#[cfg(feature = "alloc")]
379impl 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]
388 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]
396 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]
404 pub fn capacity(&self) -> usize {
405 self.events.capacity()
406 }
407
408 /// Reserves enough memory for at least `additional` more `Event`s.
409 #[inline]
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]
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]
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]
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]
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]
442 pub fn len(&mut self) -> usize {
443 self.events.len()
444 }
445
446 /// Tests whether this `EventVec` is logically empty.
447 #[inline]
448 pub fn is_empty(&mut self) -> bool {
449 self.events.is_empty()
450 }
451}
452
453#[cfg(feature = "alloc")]
454impl<'a> IntoIterator for &'a EventVec {
455 type IntoIter = Iter<'a>;
456 type Item = Event;
457
458 #[inline]
459 fn into_iter(self) -> Self::IntoIter {
460 self.iter()
461 }
462}
463
464#[test]
465fn 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