• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //!
9 //! ```rust,no_run
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;
14 //! use rustix::io::epoll::{self, Epoll};
15 //! use rustix::io::{ioctl_fionbio, read, write};
16 //! use rustix::net::{
17 //!     accept, bind_v4, listen, socket, AddressFamily, Ipv4Addr, Protocol, SocketAddrV4,
18 //!     SocketType,
19 //! };
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.
29 //! let epoll = Epoll::new(epoll::CreateFlags::CLOEXEC, epoll::Owning::new())?;
30 //!
31 //! // Remember the socket raw fd, which we use for comparisons only.
32 //! let raw_listen_sock = listen_sock.as_fd().as_raw_fd();
33 //!
34 //! // Register the socket with the epoll object.
35 //! epoll.add(listen_sock, epoll::EventFlags::IN)?;
36 //!
37 //! // Process events.
38 //! let mut event_list = epoll::EventVec::with_capacity(4);
39 //! loop {
40 //!     epoll.wait(&mut event_list, -1)?;
41 //!     for (_event_flags, target) in &event_list {
42 //!         if target.as_raw_fd() == raw_listen_sock {
43 //!             // Accept a new connection, set it to non-blocking, and
44 //!             // register to be notified when it's ready to write to.
45 //!             let conn_sock = accept(&*target)?;
46 //!             ioctl_fionbio(&conn_sock, true)?;
47 //!             epoll.add(conn_sock, epoll::EventFlags::OUT | epoll::EventFlags::ET)?;
48 //!         } else {
49 //!             // Write a message to the stream and then unregister it.
50 //!             write(&*target, b"hello\n")?;
51 //!             let _ = epoll.del(target)?;
52 //!         }
53 //!     }
54 //! }
55 //! # }
56 //! # #[cfg(not(feature = "net"))]
57 //! # fn main() {}
58 //! ```
59 
60 #![allow(unsafe_code)]
61 
62 use super::super::c;
63 use crate::backend::io::syscalls::{epoll_add, epoll_create, epoll_del, epoll_mod, epoll_wait};
64 use crate::fd::{AsFd, AsRawFd, OwnedFd};
65 #[cfg(feature = "std")]
66 use crate::fd::{BorrowedFd, FromRawFd, IntoRawFd, RawFd};
67 use crate::io;
68 use alloc::vec::Vec;
69 use bitflags::bitflags;
70 use core::marker::PhantomData;
71 use core::ptr::null;
72 
73 #[doc(inline)]
74 pub use crate::io::context::*;
75 
76 bitflags! {
77     /// `EPOLL_*` for use with [`Epoll::new`].
78     pub struct CreateFlags: c::c_uint {
79         /// `EPOLL_CLOEXEC`
80         const CLOEXEC = linux_raw_sys::general::EPOLL_CLOEXEC;
81     }
82 }
83 
84 bitflags! {
85     /// `EPOLL*` for use with [`Epoll::add`].
86     #[derive(Default)]
87     pub struct EventFlags: u32 {
88         /// `EPOLLIN`
89         const IN = linux_raw_sys::general::EPOLLIN as u32;
90 
91         /// `EPOLLOUT`
92         const OUT = linux_raw_sys::general::EPOLLOUT as u32;
93 
94         /// `EPOLLPRI`
95         const PRI = linux_raw_sys::general::EPOLLPRI as u32;
96 
97         /// `EPOLLERR`
98         const ERR = linux_raw_sys::general::EPOLLERR as u32;
99 
100         /// `EPOLLHUP`
101         const HUP = linux_raw_sys::general::EPOLLHUP as u32;
102 
103         /// `EPOLLET`
104         const ET = linux_raw_sys::general::EPOLLET as u32;
105 
106         /// `EPOLLONESHOT`
107         const ONESHOT = linux_raw_sys::general::EPOLLONESHOT as u32;
108 
109         /// `EPOLLWAKEUP`
110         const WAKEUP = linux_raw_sys::general::EPOLLWAKEUP as u32;
111 
112         /// `EPOLLEXCLUSIVE`
113         const EXCLUSIVE = linux_raw_sys::general::EPOLLEXCLUSIVE as u32;
114     }
115 }
116 
117 /// An "epoll", an interface to an OS object allowing one to repeatedly wait
118 /// for events from a set of file descriptors efficiently.
119 pub struct Epoll<Context: self::Context> {
120     epoll_fd: OwnedFd,
121     context: Context,
122 }
123 
124 impl<Context: self::Context> Epoll<Context> {
125     /// `epoll_create1(flags)`—Creates a new `Epoll`.
126     ///
127     /// Use the [`CreateFlags::CLOEXEC`] flag to prevent the resulting file
128     /// descriptor from being implicitly passed across `exec` boundaries.
129     #[inline]
130     #[doc(alias = "epoll_create1")]
new(flags: CreateFlags, context: Context) -> io::Result<Self>131     pub fn new(flags: CreateFlags, context: Context) -> io::Result<Self> {
132         // Safety: We're calling `epoll_create1` via FFI and we know how it
133         // behaves.
134         Ok(Self {
135             epoll_fd: epoll_create(flags)?,
136             context,
137         })
138     }
139 
140     /// `epoll_ctl(self, EPOLL_CTL_ADD, data, event)`—Adds an element to an
141     /// `Epoll`.
142     ///
143     /// This registers interest in any of the events set in `events` occurring
144     /// on the file descriptor associated with `data`.
145     #[doc(alias = "epoll_ctl")]
add( &self, data: Context::Data, event_flags: EventFlags, ) -> io::Result<Ref<'_, Context::Target>>146     pub fn add(
147         &self,
148         data: Context::Data,
149         event_flags: EventFlags,
150     ) -> io::Result<Ref<'_, Context::Target>> {
151         // Safety: We're calling `epoll_ctl` via FFI and we know how it
152         // behaves.
153         unsafe {
154             let target = self.context.acquire(data);
155             let raw_fd = target.as_fd().as_raw_fd();
156             let encoded = self.context.encode(target);
157             epoll_add(
158                 self.epoll_fd.as_fd(),
159                 raw_fd,
160                 &linux_raw_sys::general::epoll_event {
161                     events: event_flags.bits(),
162                     data: encoded,
163                 },
164             )?;
165             Ok(self.context.decode(encoded))
166         }
167     }
168 
169     /// `epoll_ctl(self, EPOLL_CTL_MOD, target, event)`—Modifies an element in
170     /// this `Epoll`.
171     ///
172     /// This sets the events of interest with `target` to `events`.
173     #[doc(alias = "epoll_ctl")]
mod_( &self, target: Ref<'_, Context::Target>, event_flags: EventFlags, ) -> io::Result<()>174     pub fn mod_(
175         &self,
176         target: Ref<'_, Context::Target>,
177         event_flags: EventFlags,
178     ) -> io::Result<()> {
179         let raw_fd = target.as_fd().as_raw_fd();
180         let encoded = self.context.encode(target);
181         // Safety: We're calling `epoll_ctl` via FFI and we know how it
182         // behaves.
183         unsafe {
184             epoll_mod(
185                 self.epoll_fd.as_fd(),
186                 raw_fd,
187                 &linux_raw_sys::general::epoll_event {
188                     events: event_flags.bits(),
189                     data: encoded,
190                 },
191             )
192         }
193     }
194 
195     /// `epoll_ctl(self, EPOLL_CTL_DEL, target, NULL)`—Removes an element in
196     /// this `Epoll`.
197     ///
198     /// This also returns the owning `Data`.
199     #[doc(alias = "epoll_ctl")]
del(&self, target: Ref<'_, Context::Target>) -> io::Result<Context::Data>200     pub fn del(&self, target: Ref<'_, Context::Target>) -> io::Result<Context::Data> {
201         // Safety: We're calling `epoll_ctl` via FFI and we know how it
202         // behaves.
203         unsafe {
204             let raw_fd = target.as_fd().as_raw_fd();
205             epoll_del(self.epoll_fd.as_fd(), raw_fd)?;
206         }
207         Ok(self.context.release(target))
208     }
209 
210     /// `epoll_wait(self, events, timeout)`—Waits for registered events of
211     /// interest.
212     ///
213     /// For each event of interest, an element is written to `events`. On
214     /// success, this returns the number of written elements.
215     #[doc(alias = "epoll_wait")]
wait<'context>( &'context self, event_list: &mut EventVec<'context, Context>, timeout: c::c_int, ) -> io::Result<()>216     pub fn wait<'context>(
217         &'context self,
218         event_list: &mut EventVec<'context, Context>,
219         timeout: c::c_int,
220     ) -> io::Result<()> {
221         // Safety: We're calling `epoll_wait` via FFI and we know how it
222         // behaves.
223         unsafe {
224             event_list.events.set_len(0);
225             let nfds = epoll_wait(
226                 self.epoll_fd.as_fd(),
227                 event_list.events[..].as_mut_ptr().cast(),
228                 event_list.events.capacity(),
229                 timeout,
230             )?;
231             event_list.events.set_len(nfds);
232             event_list.context = &self.context;
233         }
234 
235         Ok(())
236     }
237 }
238 
239 #[cfg(feature = "std")]
240 impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> AsRawFd for Epoll<Owning<'context, T>> {
as_raw_fd(&self) -> RawFd241     fn as_raw_fd(&self) -> RawFd {
242         self.epoll_fd.as_raw_fd()
243     }
244 }
245 
246 #[cfg(feature = "std")]
247 impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> IntoRawFd for Epoll<Owning<'context, T>> {
into_raw_fd(self) -> RawFd248     fn into_raw_fd(self) -> RawFd {
249         self.epoll_fd.into_raw_fd()
250     }
251 }
252 
253 #[cfg(feature = "std")]
254 impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> FromRawFd for Epoll<Owning<'context, T>> {
from_raw_fd(fd: RawFd) -> Self255     unsafe fn from_raw_fd(fd: RawFd) -> Self {
256         Self {
257             epoll_fd: OwnedFd::from_raw_fd(fd),
258             context: Owning::new(),
259         }
260     }
261 }
262 
263 #[cfg(feature = "std")]
264 impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> AsFd for Epoll<Owning<'context, T>> {
as_fd(&self) -> BorrowedFd<'_>265     fn as_fd(&self) -> BorrowedFd<'_> {
266         self.epoll_fd.as_fd()
267     }
268 }
269 
270 #[cfg(feature = "std")]
271 impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> From<Epoll<Owning<'context, T>>>
272     for OwnedFd
273 {
from(epoll: Epoll<Owning<'context, T>>) -> Self274     fn from(epoll: Epoll<Owning<'context, T>>) -> Self {
275         epoll.epoll_fd
276     }
277 }
278 
279 #[cfg(feature = "std")]
280 impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> From<OwnedFd>
281     for Epoll<Owning<'context, T>>
282 {
from(fd: OwnedFd) -> Self283     fn from(fd: OwnedFd) -> Self {
284         Self {
285             epoll_fd: fd,
286             context: Owning::new(),
287         }
288     }
289 }
290 
291 /// An iterator over the `Event`s in an `EventVec`.
292 pub struct Iter<'context, Context: self::Context> {
293     iter: core::slice::Iter<'context, Event>,
294     context: *const Context,
295     _phantom: PhantomData<&'context Context>,
296 }
297 
298 impl<'context, Context: self::Context> Iterator for Iter<'context, Context> {
299     type Item = (EventFlags, Ref<'context, Context::Target>);
300 
next(&mut self) -> Option<Self::Item>301     fn next(&mut self) -> Option<Self::Item> {
302         self.iter.next().map(|event| {
303             // Safety: `self.context` is guaranteed to be valid because we hold
304             // `'context` for it. And we know this event is associated with this
305             // context because `wait` sets both.
306             let decoded = unsafe { (*self.context).decode(event.encoded) };
307 
308             (event.event_flags, decoded)
309         })
310     }
311 }
312 
313 /// A record of an event that occurred.
314 #[repr(C)]
315 #[cfg_attr(target_arch = "x86_64", repr(packed))]
316 struct Event {
317     // Match the layout of `linux_raw_sys::general::epoll_event`. We just use a
318     // `u64` instead of the full union; `Context` implementations will simply
319     // need to deal with casting the value into and out of the `u64`
320     // themselves.
321     event_flags: EventFlags,
322     encoded: u64,
323 }
324 
325 /// A vector of `Event`s, plus context for interpreting them.
326 pub struct EventVec<'context, Context: self::Context> {
327     events: Vec<Event>,
328     context: *const Context,
329     _phantom: PhantomData<&'context Context>,
330 }
331 
332 impl<'context, Context: self::Context> EventVec<'context, Context> {
333     /// Constructs an `EventVec` with memory for `capacity` `Event`s.
334     #[inline]
with_capacity(capacity: usize) -> Self335     pub fn with_capacity(capacity: usize) -> Self {
336         Self {
337             events: Vec::with_capacity(capacity),
338             context: null(),
339             _phantom: PhantomData,
340         }
341     }
342 
343     /// Returns the current `Event` capacity of this `EventVec`.
344     #[inline]
capacity(&self) -> usize345     pub fn capacity(&self) -> usize {
346         self.events.capacity()
347     }
348 
349     /// Reserves enough memory for at least `additional` more `Event`s.
350     #[inline]
reserve(&mut self, additional: usize)351     pub fn reserve(&mut self, additional: usize) {
352         self.events.reserve(additional);
353     }
354 
355     /// Reserves enough memory for exactly `additional` more `Event`s.
356     #[inline]
reserve_exact(&mut self, additional: usize)357     pub fn reserve_exact(&mut self, additional: usize) {
358         self.events.reserve_exact(additional);
359     }
360 
361     /// Clears all the `Events` out of this `EventVec`.
362     #[inline]
clear(&mut self)363     pub fn clear(&mut self) {
364         self.events.clear();
365     }
366 
367     /// Shrinks the capacity of this `EventVec` as much as possible.
368     #[inline]
shrink_to_fit(&mut self)369     pub fn shrink_to_fit(&mut self) {
370         self.events.shrink_to_fit();
371     }
372 
373     /// Returns an iterator over the `Event`s in this `EventVec`.
374     #[inline]
iter(&self) -> Iter<'_, Context>375     pub fn iter(&self) -> Iter<'_, Context> {
376         Iter {
377             iter: self.events.iter(),
378             context: self.context,
379             _phantom: PhantomData,
380         }
381     }
382 
383     /// Returns the number of `Event`s logically contained in this `EventVec`.
384     #[inline]
len(&mut self) -> usize385     pub fn len(&mut self) -> usize {
386         self.events.len()
387     }
388 
389     /// Tests whether this `EventVec` is logically empty.
390     #[inline]
is_empty(&mut self) -> bool391     pub fn is_empty(&mut self) -> bool {
392         self.events.is_empty()
393     }
394 }
395 
396 impl<'context, Context: self::Context> IntoIterator for &'context EventVec<'context, Context> {
397     type IntoIter = Iter<'context, Context>;
398     type Item = (EventFlags, Ref<'context, Context::Target>);
399 
400     #[inline]
into_iter(self) -> Self::IntoIter401     fn into_iter(self) -> Self::IntoIter {
402         self.iter()
403     }
404 }
405