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 🙂.
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, ioctl_fionbio, read, write};
15 //! use rustix::net::{
16 //! accept, bind_v4, listen, socket, AddressFamily, Ipv4Addr, Protocol, SocketAddrV4,
19 //! use std::collections::HashMap;
20 //! use std::os::unix::io::AsRawFd;
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)?;
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::epoll_create(epoll::CreateFlags::CLOEXEC)?;
31 //! // Register the socket with the epoll object.
32 //! epoll::epoll_add(&epoll, &listen_sock, 1, epoll::EventFlags::IN)?;
34 //! // Keep track of the sockets we've opened.
35 //! let mut next_id = 2;
36 //! let mut sockets = HashMap::new();
38 //! // Process events.
39 //! let mut event_list = epoll::EventVec::with_capacity(4);
41 //! epoll::epoll_wait(&epoll, &mut event_list, -1)?;
42 //! for (_event_flags, target) in &event_list {
44 //! // Accept a new connection, set it to non-blocking, and
45 //! // register to be notified when it's ready to write to.
46 //! let conn_sock = accept(&listen_sock)?;
47 //! ioctl_fionbio(&conn_sock, true)?;
52 //! epoll::EventFlags::OUT | epoll::EventFlags::ET,
55 //! // Keep track of the socket.
56 //! sockets.insert(next_id, conn_sock);
59 //! // Write a message to the stream and then unregister it.
60 //! let target = sockets.remove(&target).unwrap();
61 //! write(&target, b"hello\n")?;
62 //! let _ = epoll::epoll_del(&epoll, &target)?;
67 //! # #[cfg(not(feature = "net"))]
72 use super::super::conv
::{ret, ret_owned_fd, ret_u32}
;
73 use crate::fd
::{AsFd, AsRawFd, OwnedFd}
;
76 use bitflags
::bitflags
;
77 use core
::convert
::TryInto
;
78 use core
::ptr
::null_mut
;
81 /// `EPOLL_*` for use with [`Epoll::new`].
82 pub struct CreateFlags
: c
::c_int
{
84 const CLOEXEC
= c
::EPOLL_CLOEXEC
;
89 /// `EPOLL*` for use with [`Epoll::add`].
91 pub struct EventFlags
: u32 {
93 const IN
= c
::EPOLLIN
as u32;
96 const OUT
= c
::EPOLLOUT
as u32;
99 const PRI
= c
::EPOLLPRI
as u32;
102 const ERR
= c
::EPOLLERR
as u32;
105 const HUP
= c
::EPOLLHUP
as u32;
108 const RDNORM
= c
::EPOLLRDNORM
as u32;
111 const RDBAND
= c
::EPOLLRDBAND
as u32;
114 const WRNORM
= c
::EPOLLWRNORM
as u32;
117 const WRBAND
= c
::EPOLLWRBAND
as u32;
120 const MSG
= c
::EPOLLMSG
as u32;
123 const RDHUP
= c
::EPOLLRDHUP
as u32;
126 const ET
= c
::EPOLLET
as u32;
129 const ONESHOT
= c
::EPOLLONESHOT
as u32;
132 const WAKEUP
= c
::EPOLLWAKEUP
as u32;
135 #[cfg(not(target_os = "android"))]
136 const EXCLUSIVE
= c
::EPOLLEXCLUSIVE
as u32;
140 /// `epoll_create1(flags)`—Creates a new `Epoll`.
142 /// Use the [`CreateFlags::CLOEXEC`] flag to prevent the resulting file
143 /// descriptor from being implicitly passed across `exec` boundaries.
145 #[doc(alias = "epoll_create1")]
146 pub fn epoll_create(flags
: CreateFlags
) -> io
::Result
<OwnedFd
> {
147 // SAFETY: We're calling `epoll_create1` via FFI and we know how it
149 unsafe { ret_owned_fd(c::epoll_create1(flags.bits())) }
152 /// `epoll_ctl(self, EPOLL_CTL_ADD, data, event)`—Adds an element to an
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")]
166 event_flags
: EventFlags
,
167 ) -> io
::Result
<()> {
168 // SAFETY: We're calling `epoll_ctl` via FFI and we know how it
171 let raw_fd
= source
.as_fd().as_raw_fd();
173 epoll
.as_fd().as_raw_fd(),
176 &mut c
::epoll_event
{
177 events
: event_flags
.bits(),
184 /// `epoll_ctl(self, EPOLL_CTL_MOD, target, event)`—Modifies an element in
187 /// This sets the events of interest with `target` to `events`.
188 #[doc(alias = "epoll_ctl")]
193 event_flags
: EventFlags
,
194 ) -> io
::Result
<()> {
195 let raw_fd
= source
.as_fd().as_raw_fd();
197 // SAFETY: We're calling `epoll_ctl` via FFI and we know how it
201 epoll
.as_fd().as_raw_fd(),
204 &mut c
::epoll_event
{
205 events
: event_flags
.bits(),
212 /// `epoll_ctl(self, EPOLL_CTL_DEL, target, NULL)`—Removes an element in
214 #[doc(alias = "epoll_ctl")]
215 pub 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
219 let raw_fd
= source
.as_fd().as_raw_fd();
221 epoll
.as_fd().as_raw_fd(),
229 /// `epoll_wait(self, events, timeout)`—Waits for registered events of
232 /// For each event of interest, an element is written to `events`. On
233 /// success, this returns the number of written elements.
236 event_list
: &mut EventVec
,
238 ) -> io
::Result
<()> {
239 // SAFETY: We're calling `epoll_wait` via FFI and we know how it
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
),
249 event_list
.events
.set_len(nfds
as usize);
255 /// An iterator over the `Event`s in an `EventVec`.
256 pub struct Iter
<'a
> {
257 iter
: core
::slice
::Iter
<'a
, Event
>,
260 impl<'a
> Iterator
for Iter
<'a
> {
261 type Item
= (EventFlags
, u64);
263 fn next(&mut self) -> Option
<Self::Item
> {
264 // SAFETY: `self.context` is guaranteed to be valid because we hold
265 // `'context` for it. And we know this event is associated with this
266 // context because `wait` sets both.
269 .map(|event
| (event
.event_flags
, event
.data
))
273 /// A record of an event that occurred.
279 not(target_env
= "musl"),
280 not(target_os
= "android"),
282 target_arch
= "x86_64",
287 // Match the layout of `c::epoll_event`. We just use a `u64` instead of
289 event_flags
: EventFlags
,
293 /// A vector of `Event`s, plus context for interpreting them.
294 pub struct EventVec
{
299 /// Constructs an `EventVec` with memory for `capacity` `Event`s.
301 pub fn with_capacity(capacity
: usize) -> Self {
303 events
: Vec
::with_capacity(capacity
),
307 /// Returns the current `Event` capacity of this `EventVec`.
309 pub fn capacity(&self) -> usize {
310 self.events
.capacity()
313 /// Reserves enough memory for at least `additional` more `Event`s.
315 pub fn reserve(&mut self, additional
: usize) {
316 self.events
.reserve(additional
);
319 /// Reserves enough memory for exactly `additional` more `Event`s.
321 pub fn reserve_exact(&mut self, additional
: usize) {
322 self.events
.reserve_exact(additional
);
325 /// Clears all the `Events` out of this `EventVec`.
327 pub fn clear(&mut self) {
331 /// Shrinks the capacity of this `EventVec` as much as possible.
333 pub fn shrink_to_fit(&mut self) {
334 self.events
.shrink_to_fit();
337 /// Returns an iterator over the `Event`s in this `EventVec`.
339 pub fn iter(&self) -> Iter
<'_
> {
341 iter
: self.events
.iter(),
345 /// Returns the number of `Event`s logically contained in this `EventVec`.
347 pub fn len(&mut self) -> usize {
351 /// Tests whether this `EventVec` is logically empty.
353 pub fn is_empty(&mut self) -> bool
{
354 self.events
.is_empty()
358 impl<'a
> IntoIterator
for &'a EventVec
{
359 type IntoIter
= Iter
<'a
>;
360 type Item
= (EventFlags
, u64);
363 fn into_iter(self) -> Self::IntoIter
{