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