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 use crate::backend::c;
73 #[cfg(feature = "alloc")]
74 use crate::backend::conv::ret_u32;
75 use crate::backend::conv::{ret, ret_owned_fd};
76 use crate::fd::{AsFd, AsRawFd, OwnedFd};
77 use crate::io;
78 use crate::utils::as_mut_ptr;
79 #[cfg(feature = "alloc")]
80 use alloc::vec::Vec;
81 use bitflags::bitflags;
82 use core::ffi::c_void;
83 use core::hash::{Hash, Hasher};
84 use core::ptr::null_mut;
85 use core::slice;
86
87 bitflags! {
88 /// `EPOLL_*` for use with [`new`].
89 #[repr(transparent)]
90 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
91 pub struct CreateFlags: u32 {
92 /// `EPOLL_CLOEXEC`
93 const CLOEXEC = bitcast!(c::EPOLL_CLOEXEC);
94
95 /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
96 const _ = !0;
97 }
98 }
99
100 bitflags! {
101 /// `EPOLL*` for use with [`add`].
102 #[repr(transparent)]
103 #[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Debug)]
104 pub struct EventFlags: u32 {
105 /// `EPOLLIN`
106 const IN = bitcast!(c::EPOLLIN);
107
108 /// `EPOLLOUT`
109 const OUT = bitcast!(c::EPOLLOUT);
110
111 /// `EPOLLPRI`
112 const PRI = bitcast!(c::EPOLLPRI);
113
114 /// `EPOLLERR`
115 const ERR = bitcast!(c::EPOLLERR);
116
117 /// `EPOLLHUP`
118 const HUP = bitcast!(c::EPOLLHUP);
119
120 /// `EPOLLRDNORM`
121 const RDNORM = bitcast!(c::EPOLLRDNORM);
122
123 /// `EPOLLRDBAND`
124 const RDBAND = bitcast!(c::EPOLLRDBAND);
125
126 /// `EPOLLWRNORM`
127 const WRNORM = bitcast!(c::EPOLLWRNORM);
128
129 /// `EPOLLWRBAND`
130 const WRBAND = bitcast!(c::EPOLLWRBAND);
131
132 /// `EPOLLMSG`
133 const MSG = bitcast!(c::EPOLLMSG);
134
135 /// `EPOLLRDHUP`
136 const RDHUP = bitcast!(c::EPOLLRDHUP);
137
138 /// `EPOLLET`
139 const ET = bitcast!(c::EPOLLET);
140
141 /// `EPOLLONESHOT`
142 const ONESHOT = bitcast!(c::EPOLLONESHOT);
143
144 /// `EPOLLWAKEUP`
145 const WAKEUP = bitcast!(c::EPOLLWAKEUP);
146
147 /// `EPOLLEXCLUSIVE`
148 #[cfg(not(target_os = "android"))]
149 const EXCLUSIVE = bitcast!(c::EPOLLEXCLUSIVE);
150
151 /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
152 const _ = !0;
153 }
154 }
155
156 /// `epoll_create1(flags)`—Creates a new epoll object.
157 ///
158 /// Use the [`CreateFlags::CLOEXEC`] flag to prevent the resulting file
159 /// descriptor from being implicitly passed across `exec` boundaries.
160 #[inline]
161 #[doc(alias = "epoll_create1")]
create(flags: CreateFlags) -> io::Result<OwnedFd>162 pub fn create(flags: CreateFlags) -> io::Result<OwnedFd> {
163 // SAFETY: We're calling `epoll_create1` via FFI and we know how it
164 // behaves.
165 unsafe { ret_owned_fd(c::epoll_create1(bitflags_bits!(flags))) }
166 }
167
168 /// `epoll_ctl(self, EPOLL_CTL_ADD, data, event)`—Adds an element to an epoll
169 /// object.
170 ///
171 /// This registers interest in any of the events set in `events` occurring on
172 /// the file descriptor associated with `data`.
173 ///
174 /// If [`delete`] is not called on the I/O source passed into this function
175 /// before the I/O source is `close`d, then the `epoll` will act as if the I/O
176 /// source is still registered with it. This can lead to spurious events being
177 /// returned from [`wait`]. If a file descriptor is an
178 /// `Arc<dyn SystemResource>`, then `epoll` can be thought to maintain a
179 /// `Weak<dyn SystemResource>` to the file descriptor.
180 #[doc(alias = "epoll_ctl")]
add( epoll: impl AsFd, source: impl AsFd, data: EventData, event_flags: EventFlags, ) -> io::Result<()>181 pub fn add(
182 epoll: impl AsFd,
183 source: impl AsFd,
184 data: EventData,
185 event_flags: EventFlags,
186 ) -> io::Result<()> {
187 // SAFETY: We're calling `epoll_ctl` via FFI and we know how it
188 // behaves. We use our own `Event` struct instead of libc's because
189 // ours preserves pointer provenance instead of just using a `u64`,
190 // and we have tests elsewhere for layout equivalence.
191 unsafe {
192 let raw_fd = source.as_fd().as_raw_fd();
193 ret(c::epoll_ctl(
194 epoll.as_fd().as_raw_fd(),
195 c::EPOLL_CTL_ADD,
196 raw_fd,
197 as_mut_ptr(&mut Event {
198 flags: event_flags,
199 data,
200 #[cfg(target_os = "redox")]
201 _pad: 0,
202 })
203 .cast(),
204 ))
205 }
206 }
207
208 /// `epoll_ctl(self, EPOLL_CTL_MOD, target, event)`—Modifies an element in a
209 /// given epoll object.
210 ///
211 /// This sets the events of interest with `target` to `events`.
212 #[doc(alias = "epoll_ctl")]
modify( epoll: impl AsFd, source: impl AsFd, data: EventData, event_flags: EventFlags, ) -> io::Result<()>213 pub fn modify(
214 epoll: impl AsFd,
215 source: impl AsFd,
216 data: EventData,
217 event_flags: EventFlags,
218 ) -> io::Result<()> {
219 let raw_fd = source.as_fd().as_raw_fd();
220
221 // SAFETY: We're calling `epoll_ctl` via FFI and we know how it
222 // behaves. We use our own `Event` struct instead of libc's because
223 // ours preserves pointer provenance instead of just using a `u64`,
224 // and we have tests elsewhere for layout equivalence.
225 unsafe {
226 ret(c::epoll_ctl(
227 epoll.as_fd().as_raw_fd(),
228 c::EPOLL_CTL_MOD,
229 raw_fd,
230 as_mut_ptr(&mut Event {
231 flags: event_flags,
232 data,
233 #[cfg(target_os = "redox")]
234 _pad: 0,
235 })
236 .cast(),
237 ))
238 }
239 }
240
241 /// `epoll_ctl(self, EPOLL_CTL_DEL, target, NULL)`—Removes an element in a
242 /// given epoll object.
243 #[doc(alias = "epoll_ctl")]
delete(epoll: impl AsFd, source: impl AsFd) -> io::Result<()>244 pub fn delete(epoll: impl AsFd, source: impl AsFd) -> io::Result<()> {
245 // SAFETY: We're calling `epoll_ctl` via FFI and we know how it
246 // behaves.
247 unsafe {
248 let raw_fd = source.as_fd().as_raw_fd();
249 ret(c::epoll_ctl(
250 epoll.as_fd().as_raw_fd(),
251 c::EPOLL_CTL_DEL,
252 raw_fd,
253 null_mut(),
254 ))
255 }
256 }
257
258 /// `epoll_wait(self, events, timeout)`—Waits for registered events of
259 /// interest.
260 ///
261 /// For each event of interest, an element is written to `events`. On
262 /// success, this returns the number of written elements.
263 #[cfg(feature = "alloc")]
264 #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
wait(epoll: impl AsFd, event_list: &mut EventVec, timeout: c::c_int) -> io::Result<()>265 pub fn wait(epoll: impl AsFd, event_list: &mut EventVec, timeout: c::c_int) -> io::Result<()> {
266 // SAFETY: We're calling `epoll_wait` via FFI and we know how it
267 // behaves.
268 unsafe {
269 event_list.events.set_len(0);
270 let nfds = ret_u32(c::epoll_wait(
271 epoll.as_fd().as_raw_fd(),
272 event_list.events.as_mut_ptr().cast::<c::epoll_event>(),
273 event_list.events.capacity().try_into().unwrap_or(i32::MAX),
274 timeout,
275 ))?;
276 event_list.events.set_len(nfds as usize);
277 }
278
279 Ok(())
280 }
281
282 /// An iterator over the `Event`s in an `EventVec`.
283 pub struct Iter<'a> {
284 /// Use `Copied` to copy the struct, since `Event` is `packed` on some
285 /// platforms, and it's common for users to directly destructure it, which
286 /// would lead to errors about forming references to packed fields.
287 iter: core::iter::Copied<slice::Iter<'a, Event>>,
288 }
289
290 impl<'a> Iterator for Iter<'a> {
291 type Item = Event;
292
293 #[inline]
next(&mut self) -> Option<Self::Item>294 fn next(&mut self) -> Option<Self::Item> {
295 self.iter.next()
296 }
297 }
298
299 /// A record of an event that occurred.
300 #[repr(C)]
301 #[cfg_attr(
302 all(
303 linux_kernel,
304 any(
305 all(
306 target_arch = "x86",
307 not(target_env = "musl"),
308 not(target_os = "android"),
309 ),
310 target_arch = "x86_64",
311 )
312 ),
313 repr(packed)
314 )]
315 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
316 pub struct Event {
317 /// Which specific event(s) occurred.
318 pub flags: EventFlags,
319 /// User data.
320 pub data: EventData,
321
322 #[cfg(target_os = "redox")]
323 _pad: u64,
324 }
325
326 /// Data associated with an [`Event`]. This can either be a 64-bit integer
327 /// value or a pointer which preserves pointer provenance.
328 #[repr(C)]
329 #[derive(Copy, Clone)]
330 pub union EventData {
331 /// A 64-bit integer value.
332 as_u64: u64,
333
334 /// A `*mut c_void` which preserves pointer provenance, extended to be
335 /// 64-bit so that if we read the value as a `u64` union field, we don't
336 /// get uninitialized memory.
337 sixty_four_bit_pointer: SixtyFourBitPointer,
338 }
339
340 impl EventData {
341 /// Construct a new value containing a `u64`.
342 #[inline]
new_u64(value: u64) -> Self343 pub const fn new_u64(value: u64) -> Self {
344 Self { as_u64: value }
345 }
346
347 /// Construct a new value containing a `*mut c_void`.
348 #[inline]
new_ptr(value: *mut c_void) -> Self349 pub const fn new_ptr(value: *mut c_void) -> Self {
350 Self {
351 sixty_four_bit_pointer: SixtyFourBitPointer {
352 pointer: value,
353 #[cfg(target_pointer_width = "32")]
354 _padding: 0,
355 },
356 }
357 }
358
359 /// Return the value as a `u64`.
360 ///
361 /// If the stored value was a pointer, the pointer is zero-extended to a
362 /// `u64`.
363 #[inline]
u64(self) -> u64364 pub fn u64(self) -> u64 {
365 unsafe { self.as_u64 }
366 }
367
368 /// Return the value as a `*mut c_void`.
369 ///
370 /// If the stored value was a `u64`, the least-significant bits of the
371 /// `u64` are returned as a pointer value.
372 #[inline]
ptr(self) -> *mut c_void373 pub fn ptr(self) -> *mut c_void {
374 unsafe { self.sixty_four_bit_pointer.pointer }
375 }
376 }
377
378 impl PartialEq for EventData {
379 #[inline]
eq(&self, other: &Self) -> bool380 fn eq(&self, other: &Self) -> bool {
381 self.u64() == other.u64()
382 }
383 }
384
385 impl Eq for EventData {}
386
387 impl Hash for EventData {
388 #[inline]
hash<H: Hasher>(&self, state: &mut H)389 fn hash<H: Hasher>(&self, state: &mut H) {
390 self.u64().hash(state)
391 }
392 }
393
394 #[repr(C)]
395 #[derive(Copy, Clone)]
396 struct SixtyFourBitPointer {
397 #[cfg(target_endian = "big")]
398 #[cfg(target_pointer_width = "32")]
399 _padding: u32,
400
401 pointer: *mut c_void,
402
403 #[cfg(target_endian = "little")]
404 #[cfg(target_pointer_width = "32")]
405 _padding: u32,
406 }
407
408 /// A vector of `Event`s, plus context for interpreting them.
409 #[cfg(feature = "alloc")]
410 pub struct EventVec {
411 events: Vec<Event>,
412 }
413
414 #[cfg(feature = "alloc")]
415 impl EventVec {
416 /// Constructs an `EventVec` from raw pointer, length, and capacity.
417 ///
418 /// # Safety
419 ///
420 /// This function calls [`Vec::from_raw_parts`] with its arguments.
421 ///
422 /// [`Vec::from_raw_parts`]: https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.from_raw_parts
423 #[inline]
from_raw_parts(ptr: *mut Event, len: usize, capacity: usize) -> Self424 pub unsafe fn from_raw_parts(ptr: *mut Event, len: usize, capacity: usize) -> Self {
425 Self {
426 events: Vec::from_raw_parts(ptr, len, capacity),
427 }
428 }
429
430 /// Constructs an `EventVec` with memory for `capacity` `Event`s.
431 #[inline]
with_capacity(capacity: usize) -> Self432 pub fn with_capacity(capacity: usize) -> Self {
433 Self {
434 events: Vec::with_capacity(capacity),
435 }
436 }
437
438 /// Returns the current `Event` capacity of this `EventVec`.
439 #[inline]
capacity(&self) -> usize440 pub fn capacity(&self) -> usize {
441 self.events.capacity()
442 }
443
444 /// Reserves enough memory for at least `additional` more `Event`s.
445 #[inline]
reserve(&mut self, additional: usize)446 pub fn reserve(&mut self, additional: usize) {
447 self.events.reserve(additional);
448 }
449
450 /// Reserves enough memory for exactly `additional` more `Event`s.
451 #[inline]
reserve_exact(&mut self, additional: usize)452 pub fn reserve_exact(&mut self, additional: usize) {
453 self.events.reserve_exact(additional);
454 }
455
456 /// Clears all the `Events` out of this `EventVec`.
457 #[inline]
clear(&mut self)458 pub fn clear(&mut self) {
459 self.events.clear();
460 }
461
462 /// Shrinks the capacity of this `EventVec` as much as possible.
463 #[inline]
shrink_to_fit(&mut self)464 pub fn shrink_to_fit(&mut self) {
465 self.events.shrink_to_fit();
466 }
467
468 /// Returns an iterator over the `Event`s in this `EventVec`.
469 #[inline]
iter(&self) -> Iter<'_>470 pub fn iter(&self) -> Iter<'_> {
471 Iter {
472 iter: self.events.iter().copied(),
473 }
474 }
475
476 /// Returns the number of `Event`s logically contained in this `EventVec`.
477 #[inline]
len(&mut self) -> usize478 pub fn len(&mut self) -> usize {
479 self.events.len()
480 }
481
482 /// Tests whether this `EventVec` is logically empty.
483 #[inline]
is_empty(&mut self) -> bool484 pub fn is_empty(&mut self) -> bool {
485 self.events.is_empty()
486 }
487 }
488
489 #[cfg(feature = "alloc")]
490 impl<'a> IntoIterator for &'a EventVec {
491 type IntoIter = Iter<'a>;
492 type Item = Event;
493
494 #[inline]
into_iter(self) -> Self::IntoIter495 fn into_iter(self) -> Self::IntoIter {
496 self.iter()
497 }
498 }
499
500 #[test]
test_epoll_layouts()501 fn test_epoll_layouts() {
502 check_renamed_type!(Event, epoll_event);
503 check_renamed_type!(Event, epoll_event);
504 check_renamed_struct_renamed_field!(Event, epoll_event, flags, events);
505 check_renamed_struct_renamed_field!(Event, epoll_event, data, u64);
506 }
507