• 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 use super::super::c;
61 use super::super::conv::{ret, ret_owned_fd, ret_u32};
62 use crate::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd};
63 #[cfg(not(feature = "rustc-dep-of-std"))]
64 use crate::fd::{FromRawFd, IntoRawFd};
65 use crate::io;
66 use alloc::vec::Vec;
67 use bitflags::bitflags;
68 use core::convert::TryInto;
69 use core::marker::PhantomData;
70 use core::ptr::{null, null_mut};
71 
72 #[doc(inline)]
73 pub use crate::io::context::*;
74 
75 bitflags! {
76     /// `EPOLL_*` for use with [`Epoll::new`].
77     pub struct CreateFlags: c::c_int {
78         /// `EPOLL_CLOEXEC`
79         const CLOEXEC = c::EPOLL_CLOEXEC;
80     }
81 }
82 
83 bitflags! {
84     /// `EPOLL*` for use with [`Epoll::add`].
85     #[derive(Default)]
86     pub struct EventFlags: u32 {
87         /// `EPOLLIN`
88         const IN = c::EPOLLIN as u32;
89 
90         /// `EPOLLOUT`
91         const OUT = c::EPOLLOUT as u32;
92 
93         /// `EPOLLPRI`
94         const PRI = c::EPOLLPRI as u32;
95 
96         /// `EPOLLERR`
97         const ERR = c::EPOLLERR as u32;
98 
99         /// `EPOLLHUP`
100         const HUP = c::EPOLLHUP as u32;
101 
102         /// `EPOLLET`
103         const ET = c::EPOLLET as u32;
104 
105         /// `EPOLLONESHOT`
106         const ONESHOT = c::EPOLLONESHOT as u32;
107 
108         /// `EPOLLWAKEUP`
109         const WAKEUP = c::EPOLLWAKEUP as u32;
110 
111         /// `EPOLLEXCLUSIVE`
112         #[cfg(not(target_os = "android"))]
113         const EXCLUSIVE = c::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         unsafe {
135             Ok(Self {
136                 epoll_fd: ret_owned_fd(c::epoll_create1(flags.bits()))?,
137                 context,
138             })
139         }
140     }
141 
142     /// `epoll_ctl(self, EPOLL_CTL_ADD, data, event)`—Adds an element to an
143     /// `Epoll`.
144     ///
145     /// This registers interest in any of the events set in `events` occurring
146     /// on the file descriptor associated with `data`.
147     #[doc(alias = "epoll_ctl")]
add( &self, data: Context::Data, event_flags: EventFlags, ) -> io::Result<Ref<'_, Context::Target>>148     pub fn add(
149         &self,
150         data: Context::Data,
151         event_flags: EventFlags,
152     ) -> io::Result<Ref<'_, Context::Target>> {
153         // Safety: We're calling `epoll_ctl` via FFI and we know how it
154         // behaves.
155         unsafe {
156             let target = self.context.acquire(data);
157             let raw_fd = target.as_fd().as_raw_fd();
158             let encoded = self.context.encode(target);
159             ret(c::epoll_ctl(
160                 self.epoll_fd.as_fd().as_raw_fd(),
161                 c::EPOLL_CTL_ADD,
162                 raw_fd,
163                 &mut c::epoll_event {
164                     events: event_flags.bits(),
165                     r#u64: encoded,
166                 },
167             ))?;
168             Ok(self.context.decode(encoded))
169         }
170     }
171 
172     /// `epoll_ctl(self, EPOLL_CTL_MOD, target, event)`—Modifies an element in
173     /// this `Epoll`.
174     ///
175     /// This sets the events of interest with `target` to `events`.
176     #[doc(alias = "epoll_ctl")]
mod_( &self, target: Ref<'_, Context::Target>, event_flags: EventFlags, ) -> io::Result<()>177     pub fn mod_(
178         &self,
179         target: Ref<'_, Context::Target>,
180         event_flags: EventFlags,
181     ) -> io::Result<()> {
182         let raw_fd = target.as_fd().as_raw_fd();
183         let encoded = self.context.encode(target);
184         // Safety: We're calling `epoll_ctl` via FFI and we know how it
185         // behaves.
186         unsafe {
187             ret(c::epoll_ctl(
188                 self.epoll_fd.as_fd().as_raw_fd(),
189                 c::EPOLL_CTL_MOD,
190                 raw_fd,
191                 &mut c::epoll_event {
192                     events: event_flags.bits(),
193                     r#u64: encoded,
194                 },
195             ))
196         }
197     }
198 
199     /// `epoll_ctl(self, EPOLL_CTL_DEL, target, NULL)`—Removes an element in
200     /// this `Epoll`.
201     ///
202     /// This also returns the owning `Data`.
203     #[doc(alias = "epoll_ctl")]
del(&self, target: Ref<'_, Context::Target>) -> io::Result<Context::Data>204     pub fn del(&self, target: Ref<'_, Context::Target>) -> io::Result<Context::Data> {
205         // Safety: We're calling `epoll_ctl` via FFI and we know how it
206         // behaves.
207         unsafe {
208             let raw_fd = target.as_fd().as_raw_fd();
209             ret(c::epoll_ctl(
210                 self.epoll_fd.as_fd().as_raw_fd(),
211                 c::EPOLL_CTL_DEL,
212                 raw_fd,
213                 null_mut(),
214             ))?;
215         }
216         Ok(self.context.release(target))
217     }
218 
219     /// `epoll_wait(self, events, timeout)`—Waits for registered events of
220     /// interest.
221     ///
222     /// For each event of interest, an element is written to `events`. On
223     /// success, this returns the number of written elements.
224     #[doc(alias = "epoll_wait")]
wait<'context>( &'context self, event_list: &mut EventVec<'context, Context>, timeout: c::c_int, ) -> io::Result<()>225     pub fn wait<'context>(
226         &'context self,
227         event_list: &mut EventVec<'context, Context>,
228         timeout: c::c_int,
229     ) -> io::Result<()> {
230         // Safety: We're calling `epoll_wait` via FFI and we know how it
231         // behaves.
232         unsafe {
233             event_list.events.set_len(0);
234             let nfds = ret_u32(c::epoll_wait(
235                 self.epoll_fd.as_fd().as_raw_fd(),
236                 event_list.events.as_mut_ptr().cast::<c::epoll_event>(),
237                 event_list.events.capacity().try_into().unwrap_or(i32::MAX),
238                 timeout,
239             ))?;
240             event_list.events.set_len(nfds as usize);
241             event_list.context = &self.context;
242         }
243 
244         Ok(())
245     }
246 }
247 
248 #[cfg(not(feature = "rustc-dep-of-std"))]
249 impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> AsRawFd for Epoll<Owning<'context, T>> {
as_raw_fd(&self) -> RawFd250     fn as_raw_fd(&self) -> RawFd {
251         self.epoll_fd.as_raw_fd()
252     }
253 }
254 
255 #[cfg(not(feature = "rustc-dep-of-std"))]
256 impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> IntoRawFd for Epoll<Owning<'context, T>> {
into_raw_fd(self) -> RawFd257     fn into_raw_fd(self) -> RawFd {
258         self.epoll_fd.into_raw_fd()
259     }
260 }
261 
262 #[cfg(not(feature = "rustc-dep-of-std"))]
263 impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> FromRawFd for Epoll<Owning<'context, T>> {
from_raw_fd(fd: RawFd) -> Self264     unsafe fn from_raw_fd(fd: RawFd) -> Self {
265         Self {
266             epoll_fd: OwnedFd::from_raw_fd(fd),
267             context: Owning::new(),
268         }
269     }
270 }
271 
272 #[cfg(not(feature = "rustc-dep-of-std"))]
273 impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> AsFd for Epoll<Owning<'context, T>> {
as_fd(&self) -> BorrowedFd<'_>274     fn as_fd(&self) -> BorrowedFd<'_> {
275         self.epoll_fd.as_fd()
276     }
277 }
278 
279 #[cfg(not(feature = "rustc-dep-of-std"))]
280 impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> From<Epoll<Owning<'context, T>>>
281     for OwnedFd
282 {
from(epoll: Epoll<Owning<'context, T>>) -> Self283     fn from(epoll: Epoll<Owning<'context, T>>) -> Self {
284         epoll.epoll_fd
285     }
286 }
287 
288 #[cfg(not(feature = "rustc-dep-of-std"))]
289 impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> From<OwnedFd>
290     for Epoll<Owning<'context, T>>
291 {
from(fd: OwnedFd) -> Self292     fn from(fd: OwnedFd) -> Self {
293         Self {
294             epoll_fd: fd,
295             context: Owning::new(),
296         }
297     }
298 }
299 
300 /// An iterator over the `Event`s in an `EventVec`.
301 pub struct Iter<'context, Context: self::Context> {
302     iter: core::slice::Iter<'context, Event>,
303     context: *const Context,
304     _phantom: PhantomData<&'context Context>,
305 }
306 
307 impl<'context, Context: self::Context> Iterator for Iter<'context, Context> {
308     type Item = (EventFlags, Ref<'context, Context::Target>);
309 
next(&mut self) -> Option<Self::Item>310     fn next(&mut self) -> Option<Self::Item> {
311         // Safety: `self.context` is guaranteed to be valid because we hold
312         // `'context` for it. And we know this event is associated with this
313         // context because `wait` sets both.
314         self.iter.next().map(|event| {
315             (event.event_flags, unsafe {
316                 (*self.context).decode(event.encoded)
317             })
318         })
319     }
320 }
321 
322 /// A record of an event that occurred.
323 #[repr(C)]
324 #[cfg_attr(
325     any(
326         all(
327             target_arch = "x86",
328             not(target_env = "musl"),
329             not(target_os = "android"),
330         ),
331         target_arch = "x86_64",
332     ),
333     repr(packed)
334 )]
335 struct Event {
336     // Match the layout of `c::epoll_event`. We just use a `u64` instead of
337     // the full union; `Context` implementations will simply need to deal with
338     // casting the value into and out of the `u64` themselves.
339     event_flags: EventFlags,
340     encoded: u64,
341 }
342 
343 /// A vector of `Event`s, plus context for interpreting them.
344 pub struct EventVec<'context, Context: self::Context> {
345     events: Vec<Event>,
346     context: *const Context,
347     _phantom: PhantomData<&'context Context>,
348 }
349 
350 impl<'context, Context: self::Context> EventVec<'context, Context> {
351     /// Constructs an `EventVec` with memory for `capacity` `Event`s.
352     #[inline]
with_capacity(capacity: usize) -> Self353     pub fn with_capacity(capacity: usize) -> Self {
354         Self {
355             events: Vec::with_capacity(capacity),
356             context: null(),
357             _phantom: PhantomData,
358         }
359     }
360 
361     /// Returns the current `Event` capacity of this `EventVec`.
362     #[inline]
capacity(&self) -> usize363     pub fn capacity(&self) -> usize {
364         self.events.capacity()
365     }
366 
367     /// Reserves enough memory for at least `additional` more `Event`s.
368     #[inline]
reserve(&mut self, additional: usize)369     pub fn reserve(&mut self, additional: usize) {
370         self.events.reserve(additional);
371     }
372 
373     /// Reserves enough memory for exactly `additional` more `Event`s.
374     #[inline]
reserve_exact(&mut self, additional: usize)375     pub fn reserve_exact(&mut self, additional: usize) {
376         self.events.reserve_exact(additional);
377     }
378 
379     /// Clears all the `Events` out of this `EventVec`.
380     #[inline]
clear(&mut self)381     pub fn clear(&mut self) {
382         self.events.clear();
383     }
384 
385     /// Shrinks the capacity of this `EventVec` as much as possible.
386     #[inline]
shrink_to_fit(&mut self)387     pub fn shrink_to_fit(&mut self) {
388         self.events.shrink_to_fit();
389     }
390 
391     /// Returns an iterator over the `Event`s in this `EventVec`.
392     #[inline]
iter(&self) -> Iter<'_, Context>393     pub fn iter(&self) -> Iter<'_, Context> {
394         Iter {
395             iter: self.events.iter(),
396             context: self.context,
397             _phantom: PhantomData,
398         }
399     }
400 
401     /// Returns the number of `Event`s logically contained in this `EventVec`.
402     #[inline]
len(&mut self) -> usize403     pub fn len(&mut self) -> usize {
404         self.events.len()
405     }
406 
407     /// Tests whether this `EventVec` is logically empty.
408     #[inline]
is_empty(&mut self) -> bool409     pub fn is_empty(&mut self) -> bool {
410         self.events.is_empty()
411     }
412 }
413 
414 impl<'context, Context: self::Context> IntoIterator for &'context EventVec<'context, Context> {
415     type IntoIter = Iter<'context, Context>;
416     type Item = (EventFlags, Ref<'context, Context::Target>);
417 
418     #[inline]
into_iter(self) -> Self::IntoIter419     fn into_iter(self) -> Self::IntoIter {
420         self.iter()
421     }
422 }
423