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