]> git.proxmox.com Git - rustc.git/blame - vendor/rustix/src/backend/libc/io/epoll.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / vendor / rustix / src / backend / libc / io / epoll.rs
CommitLineData
064997fb
FG
1//! epoll support.
2//!
3//! This is an experiment, and it isn't yet clear whether epoll is the right
4//! level of abstraction at which to introduce safety. But it works fairly well
5//! in simple examples 🙂.
6//!
7//! # Examples
8//!
353b0b11 9//! ```no_run
064997fb
FG
10//! # #![cfg_attr(io_lifetimes_use_std, feature(io_safety))]
11//! # #[cfg(feature = "net")]
12//! # fn main() -> std::io::Result<()> {
13//! use io_lifetimes::AsFd;
353b0b11 14//! use rustix::io::{epoll, ioctl_fionbio, read, write};
064997fb
FG
15//! use rustix::net::{
16//! accept, bind_v4, listen, socket, AddressFamily, Ipv4Addr, Protocol, SocketAddrV4,
17//! SocketType,
18//! };
353b0b11 19//! use std::collections::HashMap;
064997fb
FG
20//! use std::os::unix::io::AsRawFd;
21//!
22//! // Create a socket and listen on it.
23//! let listen_sock = socket(AddressFamily::INET, SocketType::STREAM, Protocol::default())?;
24//! bind_v4(&listen_sock, &SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0))?;
25//! listen(&listen_sock, 1)?;
26//!
27//! // Create an epoll object. Using `Owning` here means the epoll object will
28//! // take ownership of the file descriptors registered with it.
353b0b11 29//! let epoll = epoll::epoll_create(epoll::CreateFlags::CLOEXEC)?;
064997fb
FG
30//!
31//! // Register the socket with the epoll object.
353b0b11
FG
32//! epoll::epoll_add(&epoll, &listen_sock, 1, epoll::EventFlags::IN)?;
33//!
34//! // Keep track of the sockets we've opened.
35//! let mut next_id = 2;
36//! let mut sockets = HashMap::new();
064997fb
FG
37//!
38//! // Process events.
39//! let mut event_list = epoll::EventVec::with_capacity(4);
40//! loop {
353b0b11 41//! epoll::epoll_wait(&epoll, &mut event_list, -1)?;
064997fb 42//! for (_event_flags, target) in &event_list {
353b0b11 43//! if target == 1 {
064997fb
FG
44//! // Accept a new connection, set it to non-blocking, and
45//! // register to be notified when it's ready to write to.
353b0b11 46//! let conn_sock = accept(&listen_sock)?;
064997fb 47//! ioctl_fionbio(&conn_sock, true)?;
353b0b11
FG
48//! epoll::epoll_add(
49//! &epoll,
50//! &conn_sock,
51//! next_id,
52//! epoll::EventFlags::OUT | epoll::EventFlags::ET,
53//! )?;
54//!
55//! // Keep track of the socket.
56//! sockets.insert(next_id, conn_sock);
57//! next_id += 1;
064997fb
FG
58//! } else {
59//! // Write a message to the stream and then unregister it.
353b0b11
FG
60//! let target = sockets.remove(&target).unwrap();
61//! write(&target, b"hello\n")?;
62//! let _ = epoll::epoll_del(&epoll, &target)?;
064997fb
FG
63//! }
64//! }
65//! }
66//! # }
67//! # #[cfg(not(feature = "net"))]
68//! # fn main() {}
69//! ```
70
71use super::super::c;
72use super::super::conv::{ret, ret_owned_fd, ret_u32};
353b0b11 73use crate::fd::{AsFd, AsRawFd, OwnedFd};
487cf647 74use crate::io;
064997fb
FG
75use alloc::vec::Vec;
76use bitflags::bitflags;
77use core::convert::TryInto;
353b0b11 78use core::ptr::null_mut;
064997fb
FG
79
80bitflags! {
81 /// `EPOLL_*` for use with [`Epoll::new`].
82 pub struct CreateFlags: c::c_int {
83 /// `EPOLL_CLOEXEC`
84 const CLOEXEC = c::EPOLL_CLOEXEC;
85 }
86}
87
88bitflags! {
89 /// `EPOLL*` for use with [`Epoll::add`].
90 #[derive(Default)]
91 pub struct EventFlags: u32 {
92 /// `EPOLLIN`
93 const IN = c::EPOLLIN as u32;
94
95 /// `EPOLLOUT`
96 const OUT = c::EPOLLOUT as u32;
97
98 /// `EPOLLPRI`
99 const PRI = c::EPOLLPRI as u32;
100
101 /// `EPOLLERR`
102 const ERR = c::EPOLLERR as u32;
103
104 /// `EPOLLHUP`
105 const HUP = c::EPOLLHUP as u32;
106
353b0b11
FG
107 /// `EPOLLRDNORM`
108 const RDNORM = c::EPOLLRDNORM as u32;
109
110 /// `EPOLLRDBAND`
111 const RDBAND = c::EPOLLRDBAND as u32;
112
113 /// `EPOLLWRNORM`
114 const WRNORM = c::EPOLLWRNORM as u32;
115
116 /// `EPOLLWRBAND`
117 const WRBAND = c::EPOLLWRBAND as u32;
118
119 /// `EPOLLMSG`
120 const MSG = c::EPOLLMSG as u32;
121
122 /// `EPOLLRDHUP`
123 const RDHUP = c::EPOLLRDHUP as u32;
124
064997fb
FG
125 /// `EPOLLET`
126 const ET = c::EPOLLET as u32;
127
128 /// `EPOLLONESHOT`
129 const ONESHOT = c::EPOLLONESHOT as u32;
130
131 /// `EPOLLWAKEUP`
132 const WAKEUP = c::EPOLLWAKEUP as u32;
133
134 /// `EPOLLEXCLUSIVE`
135 #[cfg(not(target_os = "android"))]
136 const EXCLUSIVE = c::EPOLLEXCLUSIVE as u32;
137 }
138}
139
353b0b11 140/// `epoll_create1(flags)`—Creates a new `Epoll`.
064997fb 141///
353b0b11
FG
142/// Use the [`CreateFlags::CLOEXEC`] flag to prevent the resulting file
143/// descriptor from being implicitly passed across `exec` boundaries.
144#[inline]
145#[doc(alias = "epoll_create1")]
146pub fn epoll_create(flags: CreateFlags) -> io::Result<OwnedFd> {
147 // SAFETY: We're calling `epoll_create1` via FFI and we know how it
148 // behaves.
149 unsafe { ret_owned_fd(c::epoll_create1(flags.bits())) }
064997fb
FG
150}
151
353b0b11
FG
152/// `epoll_ctl(self, EPOLL_CTL_ADD, data, event)`—Adds an element to an
153/// `Epoll`.
154///
155/// Note that if `epoll_del` is not called on the I/O source passed into
156/// this function before the I/O source is `close`d, then the `epoll` will
157/// act as if the I/O source is still registered with it. This can lead to
158/// spurious events being returned from `epoll_wait`. If a file descriptor
159/// is an `Arc<dyn SystemResource>`, then `epoll` can be thought to maintain
160/// a `Weak<dyn SystemResource>` to the file descriptor.
161#[doc(alias = "epoll_ctl")]
162pub fn epoll_add(
163 epoll: impl AsFd,
164 source: impl AsFd,
165 data: u64,
166 event_flags: EventFlags,
167) -> io::Result<()> {
168 // SAFETY: We're calling `epoll_ctl` via FFI and we know how it
169 // behaves.
170 unsafe {
171 let raw_fd = source.as_fd().as_raw_fd();
172 ret(c::epoll_ctl(
173 epoll.as_fd().as_raw_fd(),
174 c::EPOLL_CTL_ADD,
175 raw_fd,
176 &mut c::epoll_event {
177 events: event_flags.bits(),
178 r#u64: data,
179 },
180 ))
064997fb
FG
181 }
182}
183
353b0b11
FG
184/// `epoll_ctl(self, EPOLL_CTL_MOD, target, event)`—Modifies an element in
185/// this `Epoll`.
186///
187/// This sets the events of interest with `target` to `events`.
188#[doc(alias = "epoll_ctl")]
189pub fn epoll_mod(
190 epoll: impl AsFd,
191 source: impl AsFd,
192 data: u64,
193 event_flags: EventFlags,
194) -> io::Result<()> {
195 let raw_fd = source.as_fd().as_raw_fd();
196
197 // SAFETY: We're calling `epoll_ctl` via FFI and we know how it
198 // behaves.
199 unsafe {
200 ret(c::epoll_ctl(
201 epoll.as_fd().as_raw_fd(),
202 c::EPOLL_CTL_MOD,
203 raw_fd,
204 &mut c::epoll_event {
205 events: event_flags.bits(),
206 r#u64: data,
207 },
208 ))
064997fb
FG
209 }
210}
211
353b0b11
FG
212/// `epoll_ctl(self, EPOLL_CTL_DEL, target, NULL)`—Removes an element in
213/// this `Epoll`.
214#[doc(alias = "epoll_ctl")]
215pub fn epoll_del(epoll: impl AsFd, source: impl AsFd) -> io::Result<()> {
216 // SAFETY: We're calling `epoll_ctl` via FFI and we know how it
217 // behaves.
218 unsafe {
219 let raw_fd = source.as_fd().as_raw_fd();
220 ret(c::epoll_ctl(
221 epoll.as_fd().as_raw_fd(),
222 c::EPOLL_CTL_DEL,
223 raw_fd,
224 null_mut(),
225 ))
064997fb
FG
226 }
227}
228
353b0b11
FG
229/// `epoll_wait(self, events, timeout)`—Waits for registered events of
230/// interest.
231///
232/// For each event of interest, an element is written to `events`. On
233/// success, this returns the number of written elements.
234pub fn epoll_wait(
235 epoll: impl AsFd,
236 event_list: &mut EventVec,
237 timeout: c::c_int,
238) -> io::Result<()> {
239 // SAFETY: We're calling `epoll_wait` via FFI and we know how it
240 // behaves.
241 unsafe {
242 event_list.events.set_len(0);
243 let nfds = ret_u32(c::epoll_wait(
244 epoll.as_fd().as_raw_fd(),
245 event_list.events.as_mut_ptr().cast::<c::epoll_event>(),
246 event_list.events.capacity().try_into().unwrap_or(i32::MAX),
247 timeout,
248 ))?;
249 event_list.events.set_len(nfds as usize);
250 }
251
252 Ok(())
064997fb
FG
253}
254
255/// An iterator over the `Event`s in an `EventVec`.
353b0b11
FG
256pub struct Iter<'a> {
257 iter: core::slice::Iter<'a, Event>,
064997fb
FG
258}
259
353b0b11
FG
260impl<'a> Iterator for Iter<'a> {
261 type Item = (EventFlags, u64);
064997fb
FG
262
263 fn next(&mut self) -> Option<Self::Item> {
353b0b11 264 // SAFETY: `self.context` is guaranteed to be valid because we hold
064997fb
FG
265 // `'context` for it. And we know this event is associated with this
266 // context because `wait` sets both.
353b0b11
FG
267 self.iter
268 .next()
269 .map(|event| (event.event_flags, event.data))
064997fb
FG
270 }
271}
272
273/// A record of an event that occurred.
274#[repr(C)]
275#[cfg_attr(
276 any(
277 all(
278 target_arch = "x86",
279 not(target_env = "musl"),
280 not(target_os = "android"),
281 ),
282 target_arch = "x86_64",
283 ),
284 repr(packed)
285)]
286struct Event {
287 // Match the layout of `c::epoll_event`. We just use a `u64` instead of
353b0b11 288 // the full union.
064997fb 289 event_flags: EventFlags,
353b0b11 290 data: u64,
064997fb
FG
291}
292
293/// A vector of `Event`s, plus context for interpreting them.
353b0b11 294pub struct EventVec {
064997fb 295 events: Vec<Event>,
064997fb
FG
296}
297
353b0b11 298impl EventVec {
064997fb
FG
299 /// Constructs an `EventVec` with memory for `capacity` `Event`s.
300 #[inline]
301 pub fn with_capacity(capacity: usize) -> Self {
302 Self {
303 events: Vec::with_capacity(capacity),
064997fb
FG
304 }
305 }
306
307 /// Returns the current `Event` capacity of this `EventVec`.
308 #[inline]
309 pub fn capacity(&self) -> usize {
310 self.events.capacity()
311 }
312
313 /// Reserves enough memory for at least `additional` more `Event`s.
314 #[inline]
315 pub fn reserve(&mut self, additional: usize) {
316 self.events.reserve(additional);
317 }
318
319 /// Reserves enough memory for exactly `additional` more `Event`s.
320 #[inline]
321 pub fn reserve_exact(&mut self, additional: usize) {
322 self.events.reserve_exact(additional);
323 }
324
325 /// Clears all the `Events` out of this `EventVec`.
326 #[inline]
327 pub fn clear(&mut self) {
328 self.events.clear();
329 }
330
331 /// Shrinks the capacity of this `EventVec` as much as possible.
332 #[inline]
333 pub fn shrink_to_fit(&mut self) {
334 self.events.shrink_to_fit();
335 }
336
337 /// Returns an iterator over the `Event`s in this `EventVec`.
338 #[inline]
353b0b11 339 pub fn iter(&self) -> Iter<'_> {
064997fb
FG
340 Iter {
341 iter: self.events.iter(),
064997fb
FG
342 }
343 }
344
345 /// Returns the number of `Event`s logically contained in this `EventVec`.
346 #[inline]
347 pub fn len(&mut self) -> usize {
348 self.events.len()
349 }
350
351 /// Tests whether this `EventVec` is logically empty.
352 #[inline]
353 pub fn is_empty(&mut self) -> bool {
354 self.events.is_empty()
355 }
356}
357
353b0b11
FG
358impl<'a> IntoIterator for &'a EventVec {
359 type IntoIter = Iter<'a>;
360 type Item = (EventFlags, u64);
064997fb
FG
361
362 #[inline]
363 fn into_iter(self) -> Self::IntoIter {
364 self.iter()
365 }
366}