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