diff options
Diffstat (limited to 'vendor/rustix/src/event')
| -rw-r--r-- | vendor/rustix/src/event/epoll.rs | 347 | ||||
| -rw-r--r-- | vendor/rustix/src/event/eventfd.rs | 20 | ||||
| -rw-r--r-- | vendor/rustix/src/event/kqueue.rs | 466 | ||||
| -rw-r--r-- | vendor/rustix/src/event/mod.rs | 34 | ||||
| -rw-r--r-- | vendor/rustix/src/event/pause.rs | 31 | ||||
| -rw-r--r-- | vendor/rustix/src/event/poll.rs | 47 | ||||
| -rw-r--r-- | vendor/rustix/src/event/port.rs | 197 | ||||
| -rw-r--r-- | vendor/rustix/src/event/select.rs | 391 |
8 files changed, 0 insertions, 1533 deletions
diff --git a/vendor/rustix/src/event/epoll.rs b/vendor/rustix/src/event/epoll.rs deleted file mode 100644 index 839f05de..00000000 --- a/vendor/rustix/src/event/epoll.rs +++ /dev/null @@ -1,347 +0,0 @@ -//! Linux `epoll` support. -//! -//! # Examples -//! -//! ```no_run -//! # #[cfg(feature = "net")] -//! # fn main() -> std::io::Result<()> { -//! use rustix::buffer::spare_capacity; -//! use rustix::event::epoll; -//! use rustix::fd::AsFd; -//! use rustix::io::{ioctl_fionbio, read, write}; -//! use rustix::net::{ -//! accept, bind, listen, socket, AddressFamily, Ipv4Addr, SocketAddrV4, SocketType, -//! }; -//! use std::collections::HashMap; -//! use std::os::unix::io::AsRawFd; -//! -//! // Create a socket and listen on it. -//! let listen_sock = socket(AddressFamily::INET, SocketType::STREAM, None)?; -//! bind(&listen_sock, &SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0))?; -//! listen(&listen_sock, 1)?; -//! -//! // Create an epoll object. Using `Owning` here means the epoll object will -//! // take ownership of the file descriptors registered with it. -//! let epoll = epoll::create(epoll::CreateFlags::CLOEXEC)?; -//! -//! // Register the socket with the epoll object. -//! epoll::add( -//! &epoll, -//! &listen_sock, -//! epoll::EventData::new_u64(1), -//! epoll::EventFlags::IN, -//! )?; -//! -//! // Keep track of the sockets we've opened. -//! let mut next_id = epoll::EventData::new_u64(2); -//! let mut sockets = HashMap::new(); -//! -//! // Process events. -//! let mut event_list = Vec::with_capacity(4); -//! loop { -//! epoll::wait(&epoll, spare_capacity(&mut event_list), None)?; -//! for event in event_list.drain(..) { -//! let target = event.data; -//! if target.u64() == 1 { -//! // Accept a new connection, set it to non-blocking, and -//! // register to be notified when it's ready to write to. -//! let conn_sock = accept(&listen_sock)?; -//! ioctl_fionbio(&conn_sock, true)?; -//! epoll::add( -//! &epoll, -//! &conn_sock, -//! next_id, -//! epoll::EventFlags::OUT | epoll::EventFlags::ET, -//! )?; -//! -//! // Keep track of the socket. -//! sockets.insert(next_id, conn_sock); -//! next_id = epoll::EventData::new_u64(next_id.u64() + 1); -//! } else { -//! // Write a message to the stream and then unregister it. -//! let target = sockets.remove(&target).unwrap(); -//! write(&target, b"hello\n")?; -//! let _ = epoll::delete(&epoll, &target)?; -//! } -//! } -//! } -//! # } -//! # #[cfg(not(feature = "net"))] -//! # fn main() {} -//! ``` - -#![allow(unsafe_code)] -#![allow(unused_qualifications)] - -use super::epoll; -pub use crate::backend::event::epoll::*; -use crate::backend::event::syscalls; -use crate::buffer::Buffer; -use crate::fd::{AsFd, OwnedFd}; -use crate::io; -use crate::timespec::Timespec; -use core::ffi::c_void; -use core::hash::{Hash, Hasher}; - -/// `epoll_create1(flags)`—Creates a new epoll object. -/// -/// Use the [`epoll::CreateFlags::CLOEXEC`] flag to prevent the resulting file -/// descriptor from being implicitly passed across `exec` boundaries. -/// -/// # References -/// - [Linux] -/// - [illumos] -/// -/// [Linux]: https://man7.org/linux/man-pages/man2/epoll_create.2.html -/// [illumos]: https://www.illumos.org/man/3C/epoll_create -#[inline] -#[doc(alias = "epoll_create1")] -pub fn create(flags: epoll::CreateFlags) -> io::Result<OwnedFd> { - syscalls::epoll_create(flags) -} - -/// `epoll_ctl(self, EPOLL_CTL_ADD, data, event)`—Adds an element to an epoll -/// object. -/// -/// This registers interest in any of the events set in `event_flags` occurring -/// on the file descriptor associated with `data`. -/// -/// `close`ing a file descriptor does not necessarily unregister interest which -/// can lead to spurious events being returned from [`epoll::wait`]. If a file -/// descriptor is an `Arc<dyn SystemResource>`, then `epoll` can be thought to -/// maintain a `Weak<dyn SystemResource>` to the file descriptor. Check the -/// [faq] for details. -/// -/// # References -/// - [Linux] -/// - [illumos] -/// -/// [Linux]: https://man7.org/linux/man-pages/man2/epoll_ctl.2.html -/// [illumos]: https://www.illumos.org/man/3C/epoll_ctl -/// [faq]: https://man7.org/linux/man-pages/man7/epoll.7.html#:~:text=Will%20closing%20a%20file%20descriptor%20cause%20it%20to%20be%20removed%20from%20all%0A%20%20%20%20%20%20%20%20%20%20epoll%20interest%20lists%3F -#[doc(alias = "epoll_ctl")] -#[inline] -pub fn add<EpollFd: AsFd, SourceFd: AsFd>( - epoll: EpollFd, - source: SourceFd, - data: epoll::EventData, - event_flags: epoll::EventFlags, -) -> io::Result<()> { - syscalls::epoll_add( - epoll.as_fd(), - source.as_fd(), - &Event { - flags: event_flags, - data, - #[cfg(all(libc, target_os = "redox"))] - _pad: 0, - }, - ) -} - -/// `epoll_ctl(self, EPOLL_CTL_MOD, target, event)`—Modifies an element in a -/// given epoll object. -/// -/// This sets the events of interest with `target` to `events`. -/// -/// # References -/// - [Linux] -/// - [illumos] -/// -/// [Linux]: https://man7.org/linux/man-pages/man2/epoll_ctl.2.html -/// [illumos]: https://www.illumos.org/man/3C/epoll_ctl -#[doc(alias = "epoll_ctl")] -#[inline] -pub fn modify<EpollFd: AsFd, SourceFd: AsFd>( - epoll: EpollFd, - source: SourceFd, - data: epoll::EventData, - event_flags: epoll::EventFlags, -) -> io::Result<()> { - syscalls::epoll_mod( - epoll.as_fd(), - source.as_fd(), - &Event { - flags: event_flags, - data, - #[cfg(all(libc, target_os = "redox"))] - _pad: 0, - }, - ) -} - -/// `epoll_ctl(self, EPOLL_CTL_DEL, target, NULL)`—Removes an element in a -/// given epoll object. -/// -/// # References -/// - [Linux] -/// - [illumos] -/// -/// [Linux]: https://man7.org/linux/man-pages/man2/epoll_ctl.2.html -/// [illumos]: https://www.illumos.org/man/3C/epoll_ctl -#[doc(alias = "epoll_ctl")] -#[inline] -pub fn delete<EpollFd: AsFd, SourceFd: AsFd>(epoll: EpollFd, source: SourceFd) -> io::Result<()> { - syscalls::epoll_del(epoll.as_fd(), source.as_fd()) -} - -/// `epoll_wait(self, events, timeout)`—Waits for registered events of -/// interest. -/// -/// For each event of interest, an element is written to `events`. -/// -/// Linux versions older than 5.11 (those that don't support `epoll_pwait2`) -/// don't support timeouts greater than `c_int::MAX` milliseconds; if an -/// unsupported timeout is passed, this function fails with -/// [`io::Errno::INVAL`]. Enable the "linux_5_11" feature to enable the full -/// range of timeouts. -/// -/// # References -/// - [Linux] -/// - [illumos] -/// -/// [Linux]: https://man7.org/linux/man-pages/man2/epoll_wait.2.html -/// [illumos]: https://www.illumos.org/man/3C/epoll_wait -#[doc(alias = "epoll_wait")] -#[inline] -pub fn wait<EpollFd: AsFd, Buf: Buffer<Event>>( - epoll: EpollFd, - mut event_list: Buf, - timeout: Option<&Timespec>, -) -> io::Result<Buf::Output> { - // SAFETY: `epoll_wait` behaves. - let nfds = unsafe { syscalls::epoll_wait(epoll.as_fd(), event_list.parts_mut(), timeout)? }; - // SAFETY: `epoll_wait` behaves. - unsafe { Ok(event_list.assume_init(nfds)) } -} - -/// A record of an event that occurred. -#[repr(C)] -#[cfg_attr(all(not(libc), target_arch = "x86_64"), repr(packed))] -#[cfg_attr( - all( - libc, - linux_kernel, - any( - all( - target_arch = "x86", - not(target_env = "musl"), - not(target_os = "android"), - ), - target_arch = "x86_64", - ) - ), - repr(packed) -)] -#[cfg_attr( - all(solarish, any(target_arch = "x86", target_arch = "x86_64")), - repr(packed(4)) -)] -#[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub struct Event { - /// Which specific event(s) occurred. - pub flags: EventFlags, - /// User data. - pub data: EventData, - - #[cfg(all(libc, target_os = "redox"))] - _pad: u64, -} - -/// Data associated with an [`epoll::Event`]. This can either be a 64-bit -/// integer value or a pointer which preserves pointer provenance. -#[repr(C)] -#[derive(Copy, Clone)] -pub union EventData { - /// A 64-bit integer value. - as_u64: u64, - - /// A `*mut c_void` which preserves pointer provenance, extended to be - /// 64-bit so that if we read the value as a `u64` union field, we don't - /// get uninitialized memory. - sixty_four_bit_pointer: SixtyFourBitPointer, -} - -impl EventData { - /// Construct a new value containing a `u64`. - #[inline] - pub const fn new_u64(value: u64) -> Self { - Self { as_u64: value } - } - - /// Construct a new value containing a `*mut c_void`. - #[inline] - pub const fn new_ptr(value: *mut c_void) -> Self { - Self { - sixty_four_bit_pointer: SixtyFourBitPointer { - pointer: value, - #[cfg(target_pointer_width = "32")] - _padding: 0, - }, - } - } - - /// Return the value as a `u64`. - /// - /// If the stored value was a pointer, the pointer is zero-extended to a - /// `u64`. - #[inline] - pub fn u64(self) -> u64 { - unsafe { self.as_u64 } - } - - /// Return the value as a `*mut c_void`. - /// - /// If the stored value was a `u64`, the least-significant bits of the - /// `u64` are returned as a pointer value. - #[inline] - pub fn ptr(self) -> *mut c_void { - unsafe { self.sixty_four_bit_pointer.pointer } - } -} - -impl PartialEq for EventData { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.u64() == other.u64() - } -} - -impl Eq for EventData {} - -impl Hash for EventData { - #[inline] - fn hash<H: Hasher>(&self, state: &mut H) { - self.u64().hash(state) - } -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct SixtyFourBitPointer { - #[cfg(target_endian = "big")] - #[cfg(target_pointer_width = "32")] - _padding: u32, - - pointer: *mut c_void, - - #[cfg(target_endian = "little")] - #[cfg(target_pointer_width = "32")] - _padding: u32, -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::backend::c; - - #[test] - fn test_epoll_layouts() { - check_renamed_type!(Event, epoll_event); - check_renamed_struct_renamed_field!(Event, epoll_event, flags, events); - #[cfg(libc)] - check_renamed_struct_renamed_field!(Event, epoll_event, data, u64); - #[cfg(not(libc))] - check_renamed_struct_renamed_field!(Event, epoll_event, data, data); - } -} diff --git a/vendor/rustix/src/event/eventfd.rs b/vendor/rustix/src/event/eventfd.rs deleted file mode 100644 index a76f2cfc..00000000 --- a/vendor/rustix/src/event/eventfd.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::fd::OwnedFd; -use crate::{backend, io}; - -pub use backend::event::types::EventfdFlags; - -/// `eventfd(initval, flags)`—Creates a file descriptor for event -/// notification. -/// -/// # References -/// - [Linux] -/// - [FreeBSD] -/// - [illumos] -/// -/// [Linux]: https://man7.org/linux/man-pages/man2/eventfd.2.html -/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?eventfd -/// [illumos]: https://illumos.org/man/3C/eventfd -#[inline] -pub fn eventfd(initval: u32, flags: EventfdFlags) -> io::Result<OwnedFd> { - backend::event::syscalls::eventfd(initval, flags) -} diff --git a/vendor/rustix/src/event/kqueue.rs b/vendor/rustix/src/event/kqueue.rs deleted file mode 100644 index 897d9398..00000000 --- a/vendor/rustix/src/event/kqueue.rs +++ /dev/null @@ -1,466 +0,0 @@ -//! An API for interfacing with `kqueue`. - -use crate::buffer::Buffer; -use crate::fd::{AsFd, OwnedFd, RawFd}; -use crate::pid::Pid; -use crate::signal::Signal; -use crate::timespec::Timespec; -use crate::{backend, io}; - -use backend::c::{self, intptr_t, kevent as kevent_t, uintptr_t}; -use backend::event::syscalls; - -use core::mem::zeroed; -use core::time::Duration; - -/// A `kqueue` event for use with [`kevent`]. -#[repr(transparent)] -#[derive(Copy, Clone)] -pub struct Event { - // The layout varies between BSDs and macOS. - inner: kevent_t, -} - -impl Event { - /// Create a new `Event`. - #[allow(clippy::needless_update)] - pub fn new(filter: EventFilter, flags: EventFlags, udata: *mut c::c_void) -> Event { - let (ident, data, filter, fflags) = match filter { - EventFilter::Read(fd) => (fd as uintptr_t, 0, c::EVFILT_READ, 0), - EventFilter::Write(fd) => (fd as _, 0, c::EVFILT_WRITE, 0), - #[cfg(target_os = "freebsd")] - EventFilter::Empty(fd) => (fd as _, 0, c::EVFILT_EMPTY, 0), - EventFilter::Vnode { vnode, flags } => (vnode as _, 0, c::EVFILT_VNODE, flags.bits()), - EventFilter::Proc { pid, flags } => { - (Pid::as_raw(Some(pid)) as _, 0, c::EVFILT_PROC, flags.bits()) - } - EventFilter::Signal { signal, times: _ } => { - (signal.as_raw() as _, 0, c::EVFILT_SIGNAL, 0) - } - EventFilter::Timer { ident, timer } => { - #[cfg(any(apple, target_os = "freebsd", target_os = "netbsd"))] - let (data, fflags) = match timer { - Some(timer) => { - if timer.subsec_millis() == 0 { - (timer.as_secs() as _, c::NOTE_SECONDS) - } else if timer.subsec_nanos() == 0 { - (timer.as_micros() as _, c::NOTE_USECONDS) - } else { - (timer.as_nanos() as _, c::NOTE_NSECONDS) - } - } - None => (intptr_t::MAX, c::NOTE_SECONDS), - }; - #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))] - let (data, fflags) = match timer { - Some(timer) => (timer.as_millis() as _, 0), - None => (intptr_t::MAX, 0), - }; - - (ident as _, data, c::EVFILT_TIMER, fflags) - } - #[cfg(any(apple, freebsdlike))] - EventFilter::User { - ident, - flags, - user_flags, - } => (ident as _, 0, c::EVFILT_USER, flags.bits() | user_flags.0), - EventFilter::Unknown => panic!("unknown filter"), - }; - - Event { - inner: kevent_t { - ident, - filter: filter as _, - flags: flags.bits() as _, - fflags, - data: { - // On OpenBSD, data is an `i64` and not an `isize`. - data as _ - }, - udata: { - // On NetBSD, udata is an `isize` and not a pointer. - udata as _ - }, - ..unsafe { zeroed() } - }, - } - } - - /// Get the event flags for this event. - pub fn flags(&self) -> EventFlags { - EventFlags::from_bits_retain(self.inner.flags as _) - } - - /// Get the user data for this event. - pub fn udata(&self) -> *mut c::c_void { - // On NetBSD, udata is an isize and not a pointer. - self.inner.udata as _ - } - - /// Get the raw data for this event. - pub fn data(&self) -> i64 { - // On some BSDs, data is an `isize` and not an `i64`. - self.inner.data as _ - } - - /// Get the filter of this event. - pub fn filter(&self) -> EventFilter { - match self.inner.filter as _ { - c::EVFILT_READ => EventFilter::Read(self.inner.ident as _), - c::EVFILT_WRITE => EventFilter::Write(self.inner.ident as _), - #[cfg(target_os = "freebsd")] - c::EVFILT_EMPTY => EventFilter::Empty(self.inner.ident as _), - c::EVFILT_VNODE => EventFilter::Vnode { - vnode: self.inner.ident as _, - flags: VnodeEvents::from_bits_retain(self.inner.fflags), - }, - c::EVFILT_PROC => EventFilter::Proc { - pid: Pid::from_raw(self.inner.ident as _).unwrap(), - flags: ProcessEvents::from_bits_retain(self.inner.fflags), - }, - c::EVFILT_SIGNAL => EventFilter::Signal { - // SAFETY: `EventFilter::new` requires a valid `Signal`. - signal: unsafe { Signal::from_raw_unchecked(self.inner.ident as _) }, - times: self.inner.data as _, - }, - c::EVFILT_TIMER => EventFilter::Timer { - ident: self.inner.ident as _, - timer: { - let (data, fflags) = (self.inner.data, self.inner.fflags); - #[cfg(not(any(apple, target_os = "freebsd", target_os = "netbsd")))] - let _ = fflags; - #[cfg(any(apple, target_os = "freebsd", target_os = "netbsd"))] - match fflags as _ { - c::NOTE_SECONDS => Some(Duration::from_secs(data as _)), - c::NOTE_USECONDS => Some(Duration::from_micros(data as _)), - c::NOTE_NSECONDS => Some(Duration::from_nanos(data as _)), - _ => { - // Unknown timer flags. - None - } - } - #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))] - Some(Duration::from_millis(data as _)) - }, - }, - #[cfg(any(apple, freebsdlike))] - c::EVFILT_USER => EventFilter::User { - ident: self.inner.ident as _, - flags: UserFlags::from_bits_retain(self.inner.fflags), - user_flags: UserDefinedFlags(self.inner.fflags & EVFILT_USER_FLAGS), - }, - _ => EventFilter::Unknown, - } - } -} - -/// Bottom 24 bits of a `u32`. -#[cfg(any(apple, freebsdlike))] -const EVFILT_USER_FLAGS: u32 = 0x00ff_ffff; - -/// The possible filters for a `kqueue`. -#[repr(i16)] -#[non_exhaustive] -pub enum EventFilter { - /// A read filter. - Read(RawFd), - - /// A write filter. - Write(RawFd), - - /// An empty filter. - #[cfg(target_os = "freebsd")] - Empty(RawFd), - - /// A VNode filter. - Vnode { - /// The file descriptor we looked for events in. - vnode: RawFd, - - /// The flags for this event. - flags: VnodeEvents, - }, - - /// A process filter. - Proc { - /// The process ID we waited on. - pid: Pid, - - /// The flags for this event. - flags: ProcessEvents, - }, - - /// A signal filter. - Signal { - /// The signal number we waited on. - signal: Signal, - - /// The number of times the signal has been received since the last - /// call to kevent. - times: usize, - }, - - /// A timer filter. - Timer { - /// The identifier for this event. - ident: intptr_t, - - /// The duration for this event. - timer: Option<Duration>, - }, - - /// A user filter. - #[cfg(any(apple, freebsdlike))] - User { - /// The identifier for this event. - ident: intptr_t, - - /// The flags for this event. - flags: UserFlags, - - /// The user-defined flags for this event. - user_flags: UserDefinedFlags, - }, - - /// This filter is unknown. - /// - /// # Panics - /// - /// Passing this into `Event::new()` will result in a panic. - Unknown, -} - -bitflags::bitflags! { - /// The flags for a `kqueue` event specifying actions to perform. - #[repr(transparent)] - #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] - pub struct EventFlags: u16 { - /// Add the event to the `kqueue`. - const ADD = c::EV_ADD as _; - - /// Enable the event. - const ENABLE = c::EV_ENABLE as _; - - /// Disable the event. - const DISABLE = c::EV_DISABLE as _; - - /// Delete the event from the `kqueue`. - const DELETE = c::EV_DELETE as _; - - /// TODO - const RECEIPT = c::EV_RECEIPT as _; - - /// Clear the event after it is triggered. - const ONESHOT = c::EV_ONESHOT as _; - - /// TODO - const CLEAR = c::EV_CLEAR as _; - - /// TODO - const EOF = c::EV_EOF as _; - - /// TODO - const ERROR = c::EV_ERROR as _; - - /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> - const _ = !0; - } -} - -bitflags::bitflags! { - /// The flags for a virtual node event. - #[repr(transparent)] - #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] - pub struct VnodeEvents: u32 { - /// The file was deleted. - const DELETE = c::NOTE_DELETE; - - /// The file was written to. - const WRITE = c::NOTE_WRITE; - - /// The file was extended. - const EXTEND = c::NOTE_EXTEND; - - /// The file had its attributes changed. - const ATTRIBUTES = c::NOTE_ATTRIB; - - /// The file was renamed. - const RENAME = c::NOTE_RENAME; - - /// Access to the file was revoked. - const REVOKE = c::NOTE_REVOKE; - - /// The link count of the file has changed. - const LINK = c::NOTE_LINK; - - /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> - const _ = !0; - } -} - -bitflags::bitflags! { - /// The flags for a process event. - #[repr(transparent)] - #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] - pub struct ProcessEvents: u32 { - /// The process exited. - const EXIT = c::NOTE_EXIT; - - /// The process forked itself. - const FORK = c::NOTE_FORK; - - /// The process executed a new process. - const EXEC = c::NOTE_EXEC; - - /// Follow the process through `fork` calls (write only). - const TRACK = c::NOTE_TRACK; - - /// An error has occurred with following the process. - const TRACKERR = c::NOTE_TRACKERR; - - /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> - const _ = !0; - } -} - -#[cfg(any(apple, freebsdlike))] -bitflags::bitflags! { - /// The flags for a user event. - #[repr(transparent)] - #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] - pub struct UserFlags: u32 { - /// Ignore the user input flags. - #[doc(alias = "NOP")] - const NOINPUT = c::NOTE_FFNOP; - - /// Bitwise AND `fflags`. - const AND = c::NOTE_FFAND; - - /// Bitwise OR `fflags`. - const OR = c::NOTE_FFOR; - - /// Copy `fflags`. - const COPY = c::NOTE_FFCOPY; - - /// Control mask for operations. - const CTRLMASK = c::NOTE_FFCTRLMASK; - - /// User defined flags for masks. - const UDFMASK = c::NOTE_FFLAGSMASK; - - /// Trigger the event. - const TRIGGER = c::NOTE_TRIGGER; - - /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> - const _ = !0; - } -} - -/// User-defined flags. -/// -/// Only the lower 24 bits are used in this struct. -#[repr(transparent)] -#[cfg(any(apple, freebsdlike))] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct UserDefinedFlags(u32); - -#[cfg(any(apple, freebsdlike))] -impl UserDefinedFlags { - /// Create a new `UserDefinedFlags` from a `u32`. - pub fn new(flags: u32) -> Self { - Self(flags & EVFILT_USER_FLAGS) - } - - /// Get the underlying `u32`. - pub fn get(self) -> u32 { - self.0 - } -} - -/// `kqueue()`—Create a new `kqueue` file descriptor. -/// -/// # References -/// - [Apple] -/// - [FreeBSD] -/// - [OpenBSD] -/// - [NetBSD] -/// - [DragonFly BSD] -/// -/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/kqueue.2.html -/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2 -/// [OpenBSD]: https://man.openbsd.org/kqueue.2 -/// [NetBSD]: https://man.netbsd.org/kqueue.2 -/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=kqueue§ion=2 -pub fn kqueue() -> io::Result<OwnedFd> { - syscalls::kqueue() -} - -/// `kevent(kqueue, changelist, eventlist, timeout)`—Wait for events on a -/// `kqueue`. -/// -/// If an unsupported timeout is passed, this function fails with -/// [`io::Errno::INVAL`]. -/// -/// # Safety -/// -/// The file descriptors referred to by the `Event` structs must be valid for -/// the lifetime of the `kqueue` file descriptor. -/// -/// # References -/// - [Apple] -/// - [FreeBSD] -/// - [OpenBSD] -/// - [NetBSD] -/// - [DragonFly BSD] -/// -/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/kevent.2.html -/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=kevent&sektion=2 -/// [OpenBSD]: https://man.openbsd.org/kevent.2 -/// [NetBSD]: https://man.netbsd.org/kevent.2 -/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=kevent§ion=2 -pub unsafe fn kevent_timespec<Fd: AsFd, Buf: Buffer<Event>>( - kqueue: Fd, - changelist: &[Event], - mut eventlist: Buf, - timeout: Option<&Timespec>, -) -> io::Result<Buf::Output> { - // Populate the event list with events. - let len = syscalls::kevent(kqueue.as_fd(), changelist, eventlist.parts_mut(), timeout) - .map(|res| res as _)?; - - Ok(eventlist.assume_init(len)) -} - -/// `kevent(kqueue, changelist, eventlist, timeout)`—Wait for events on a -/// `kqueue`. -/// -/// This is a wrapper around [`kevent_timespec`] which takes a `Duration` -/// instead of a `Timespec` for the timemout value. `Timespec` has a signed -/// `i64` seconds field; if converting `Duration` to `Timespec` overflows, -/// `None` is passed as the timeout instead, such such a large timeout would -/// be effectively infinite in practice. -/// -/// # Safety -/// -/// The file descriptors referred to by the `Event` structs must be valid for -/// the lifetime of the `kqueue` file descriptor. -pub unsafe fn kevent<Fd: AsFd, Buf: Buffer<Event>>( - kqueue: Fd, - changelist: &[Event], - eventlist: Buf, - timeout: Option<Duration>, -) -> io::Result<Buf::Output> { - let timeout = match timeout { - Some(timeout) => match timeout.as_secs().try_into() { - Ok(tv_sec) => Some(Timespec { - tv_sec, - tv_nsec: timeout.subsec_nanos() as _, - }), - Err(_) => None, - }, - None => None, - }; - - kevent_timespec(kqueue, changelist, eventlist, timeout.as_ref()) -} diff --git a/vendor/rustix/src/event/mod.rs b/vendor/rustix/src/event/mod.rs deleted file mode 100644 index 29dfc227..00000000 --- a/vendor/rustix/src/event/mod.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! Event operations. - -#[cfg(any(linux_kernel, target_os = "illumos", target_os = "redox"))] -pub mod epoll; -#[cfg(any( - linux_kernel, - target_os = "freebsd", - target_os = "illumos", - target_os = "espidf" -))] -mod eventfd; -#[cfg(bsd)] -pub mod kqueue; -#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] -mod pause; -mod poll; -#[cfg(solarish)] -pub mod port; -#[cfg(any(bsd, linux_kernel, windows, target_os = "wasi"))] -mod select; - -pub use crate::timespec::{Nsecs, Secs, Timespec}; -#[cfg(any( - linux_kernel, - target_os = "freebsd", - target_os = "illumos", - target_os = "espidf" -))] -pub use eventfd::{eventfd, EventfdFlags}; -#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] -pub use pause::*; -pub use poll::{poll, PollFd, PollFlags}; -#[cfg(any(bsd, linux_kernel, windows, target_os = "wasi"))] -pub use select::*; diff --git a/vendor/rustix/src/event/pause.rs b/vendor/rustix/src/event/pause.rs deleted file mode 100644 index 41103011..00000000 --- a/vendor/rustix/src/event/pause.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::backend; - -/// `pause()`—Sleep until interrupted by a signal. -/// -/// The POSIX `pause` interface returns an error code, but the only thing -/// `pause` does is sleep until interrupted by a signal. If it were exposed in -/// the API here it would always return `Errno::INTR`, so for simplicity the -/// return value is omitted. -/// -/// # References -/// - [POSIX] -/// - [Linux] -/// - [Apple] -/// - [FreeBSD] -/// - [NetBSD] -/// - [OpenBSD] -/// - [DragonFly BSD] -/// - [illumos] -/// -/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/pause.html -/// [Linux]: https://man7.org/linux/man-pages/man2/pause.2.html -/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/pause.3.html -/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=pause&sektion=3 -/// [NetBSD]: https://man.netbsd.org/pause.3 -/// [OpenBSD]: https://man.openbsd.org/pause.3 -/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pause§ion=3 -/// [illumos]: https://illumos.org/man/2/pause -#[inline] -pub fn pause() { - backend::event::syscalls::pause() -} diff --git a/vendor/rustix/src/event/poll.rs b/vendor/rustix/src/event/poll.rs deleted file mode 100644 index bf25fd5d..00000000 --- a/vendor/rustix/src/event/poll.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::event::Timespec; -use crate::{backend, io}; - -pub use backend::event::poll_fd::{PollFd, PollFlags}; - -/// `poll(self.fds, timeout)`—Wait for events on lists of file descriptors. -/// -/// Some platforms (those that don't support `ppoll`) don't support timeouts -/// greater than `c_int::MAX` milliseconds; if an unsupported timeout is -/// passed, this function fails with [`io::Errno::INVAL`]. -/// -/// On macOS, `poll` doesn't work on fds for /dev/tty or /dev/null, however -/// [`select`] is available and does work on these fds. -/// -/// [`select`]: crate::event::select() -/// -/// This function does not use the [`Buffer`] trait because the `fds` list is -/// both an input and output buffer. -/// -/// [`Buffer`]: crate::buffer::Buffer -/// -/// # References -/// - [Beej's Guide to Network Programming] -/// - [POSIX] -/// - [Linux] -/// - [Apple] -/// - [Winsock] -/// - [FreeBSD] -/// - [NetBSD] -/// - [OpenBSD] -/// - [DragonFly BSD] -/// - [illumos] -/// -/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/slightly-advanced-techniques.html#poll -/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/poll.html -/// [Linux]: https://man7.org/linux/man-pages/man2/poll.2.html -/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/poll.2.html -/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsapoll -/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=poll&sektion=2 -/// [NetBSD]: https://man.netbsd.org/poll.2 -/// [OpenBSD]: https://man.openbsd.org/poll.2 -/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=poll§ion=2 -/// [illumos]: https://illumos.org/man/2/poll -#[inline] -pub fn poll(fds: &mut [PollFd<'_>], timeout: Option<&Timespec>) -> io::Result<usize> { - backend::event::syscalls::poll(fds, timeout) -} diff --git a/vendor/rustix/src/event/port.rs b/vendor/rustix/src/event/port.rs deleted file mode 100644 index 7cc5f939..00000000 --- a/vendor/rustix/src/event/port.rs +++ /dev/null @@ -1,197 +0,0 @@ -//! Solaris/illumos event ports. -//! -//! # Examples -//! -//! ``` -//! # fn test() -> std::io::Result<()> { -//! use rustix::event::port; -//! use rustix::stdio::stdout; -//! use std::io; -//! -//! let some_fd = stdout(); -//! let some_userdata = 7 as *mut _; -//! -//! // Create a port. -//! let port = port::create()?; -//! -//! // Associate `some_fd` with the port. -//! unsafe { -//! port::associate_fd(&port, some_fd, port::PollFlags::IN, some_userdata)?; -//! } -//! -//! // Get a single event. -//! let event = port::get(&port, None)?; -//! -//! assert_eq!(event.userdata(), some_userdata); -//! # Ok(()) -//! # } -//! ``` - -use crate::backend::c; -use crate::backend::event::syscalls; -use crate::buffer::Buffer; -use crate::fd::{AsFd, AsRawFd, OwnedFd}; -use crate::timespec::Timespec; -use crate::{ffi, io}; - -pub use super::PollFlags; - -/// The structure representing a port event. -#[repr(transparent)] -#[doc(alias = "port_event")] -pub struct Event(pub(crate) c::port_event); - -impl Event { - /// Get the events associated with this event. - pub fn events(&self) -> i32 { - self.0.portev_events - } - - /// Get the event source associated with this event. - pub fn object(&self) -> usize { - self.0.portev_object - } - - /// Get the userdata associated with this event. - pub fn userdata(&self) -> *mut ffi::c_void { - self.0.portev_user - } -} - -/// `port_create()`—Creates a new port. -/// -/// # References -/// - [OpenSolaris] -/// - [illumos] -/// -/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_create/ -/// [illumos]: https://illumos.org/man/3C/port_create -#[doc(alias = "port_create")] -pub fn create() -> io::Result<OwnedFd> { - syscalls::port_create() -} - -/// `port_associate(_, PORT_SOURCE_FD, _, _, _)`—Associates a file descriptor -/// with a port. -/// -/// # Safety -/// -/// Any `object`s passed into the `port` must be valid for the lifetime of the -/// `port`. Logically, `port` keeps a borrowed reference to the `object` until -/// it is removed via [`dissociate_fd`]. -/// -/// # References -/// - [OpenSolaris] -/// - [illumos] -/// -/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_associate/ -/// [illumos]: https://illumos.org/man/3C/port_associate -#[doc(alias = "port_associate")] -pub unsafe fn associate_fd<Fd: AsFd, RawFd: AsRawFd>( - port: Fd, - object: RawFd, - events: PollFlags, - userdata: *mut ffi::c_void, -) -> io::Result<()> { - syscalls::port_associate( - port.as_fd(), - c::PORT_SOURCE_FD, - object.as_raw_fd() as _, - events.bits() as _, - userdata.cast(), - ) -} - -/// `port_dissociate(_, PORT_SOURCE_FD, _)`—Dissociates a file descriptor -/// from a port. -/// -/// # Safety -/// -/// The file descriptor passed into this function must have been previously -/// associated with the port via [`associate_fd`]. -/// -/// # References -/// - [OpenSolaris] -/// - [illumos] -/// -/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_dissociate -/// [illumos]: https://illumos.org/man/3C/port_dissociate -#[doc(alias = "port_dissociate")] -pub unsafe fn dissociate_fd<Fd: AsFd, RawFd: AsRawFd>(port: Fd, object: RawFd) -> io::Result<()> { - syscalls::port_dissociate(port.as_fd(), c::PORT_SOURCE_FD, object.as_raw_fd() as _) -} - -/// `port_get(port, timeout)`—Gets an event from a port. -/// -/// If an unsupported timeout is passed, this function fails with -/// [`io::Errno::INVAL`]. -/// -/// # References -/// - [OpenSolaris] -/// - [illumos] -/// -/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_get/ -/// [illumos]: https://illumos.org/man/3C/port_get -#[doc(alias = "port_get")] -pub fn get<Fd: AsFd>(port: Fd, timeout: Option<&Timespec>) -> io::Result<Event> { - syscalls::port_get(port.as_fd(), timeout) -} - -/// `port_getn(port, events, min_events, timeout)`—Gets multiple events from -/// a port. -/// -/// If `events` is empty, this does nothing and returns immediately. -/// -/// To query the number of events without retrieving any, use [`getn_query`]. -/// -/// If an unsupported timeout is passed, this function fails with -/// [`io::Errno::INVAL`]. -/// -/// # References -/// - [OpenSolaris] -/// - [illumos] -/// -/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_getn/ -/// [illumos]: https://illumos.org/man/3C/port_getn -#[doc(alias = "port_getn")] -pub fn getn<Fd: AsFd, Buf: Buffer<Event>>( - port: Fd, - mut events: Buf, - min_events: u32, - timeout: Option<&Timespec>, -) -> io::Result<Buf::Output> { - // SAFETY: `port_getn` behaves. - let nevents = - unsafe { syscalls::port_getn(port.as_fd(), events.parts_mut(), min_events, timeout)? }; - // SAFETY: `port_getn` behaves. - unsafe { Ok(events.assume_init(nevents)) } -} - -/// `port_getn(port, NULL, 0, NULL)`—Queries the number of events -/// available from a port. -/// -/// To retrieve the events, use [`getn`]. -/// -/// # References -/// - [OpenSolaris] -/// - [illumos] -/// -/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_getn/ -/// [illumos]: https://illumos.org/man/3C/port_getn -#[doc(alias = "port_getn")] -pub fn getn_query<Fd: AsFd>(port: Fd) -> io::Result<u32> { - syscalls::port_getn_query(port.as_fd()) -} - -/// `port_send(port, events, userdata)`—Sends an event to a port. -/// -/// # References -/// - [OpenSolaris] -/// - [illumos] -/// -/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_send/ -/// [illumos]: https://illumos.org/man/3C/port_send -#[doc(alias = "port_send")] -pub fn send<Fd: AsFd>(port: Fd, events: i32, userdata: *mut ffi::c_void) -> io::Result<()> { - syscalls::port_send(port.as_fd(), events, userdata.cast()) -} diff --git a/vendor/rustix/src/event/select.rs b/vendor/rustix/src/event/select.rs deleted file mode 100644 index 6bb93b53..00000000 --- a/vendor/rustix/src/event/select.rs +++ /dev/null @@ -1,391 +0,0 @@ -//! The `select` function. -//! -//! # Safety -//! -//! `select` is unsafe due to I/O safety. -#![allow(unsafe_code)] - -#[cfg(any(linux_like, target_os = "wasi"))] -use crate::backend::c; -use crate::event::Timespec; -use crate::fd::RawFd; -use crate::{backend, io}; -#[cfg(any(windows, target_os = "wasi"))] -use core::mem::align_of; -use core::mem::size_of; - -/// wasi-libc's `fd_set` type. The libc bindings for it have private fields, so -/// we redeclare it for ourselves so that we can access the fields. They're -/// publicly exposed in wasi-libc. -#[cfg(target_os = "wasi")] -#[repr(C)] -struct FD_SET { - /// The wasi-libc headers call this `__nfds`. - fd_count: usize, - /// The wasi-libc headers call this `__fds`. - fd_array: [i32; c::FD_SETSIZE], -} - -#[cfg(windows)] -use windows_sys::Win32::Networking::WinSock::FD_SET; - -/// Storage element type for use with [`select`]. -#[cfg(all( - target_pointer_width = "64", - any(windows, target_os = "freebsd", target_os = "dragonfly") -))] -#[repr(transparent)] -#[derive(Copy, Clone, Default)] -pub struct FdSetElement(pub(crate) u64); - -/// Storage element type for use with [`select`]. -#[cfg(linux_like)] -#[repr(transparent)] -#[derive(Copy, Clone, Default)] -pub struct FdSetElement(pub(crate) c::c_ulong); - -/// Storage element type for use with [`select`]. -#[cfg(not(any( - linux_like, - target_os = "wasi", - all( - target_pointer_width = "64", - any(windows, target_os = "freebsd", target_os = "dragonfly") - ) -)))] -#[repr(transparent)] -#[derive(Copy, Clone, Default)] -pub struct FdSetElement(pub(crate) u32); - -/// Storage element type for use with [`select`]. -#[cfg(target_os = "wasi")] -#[repr(transparent)] -#[derive(Copy, Clone, Default)] -pub struct FdSetElement(pub(crate) usize); - -/// `select(nfds, readfds, writefds, exceptfds, timeout)`—Wait for events on -/// sets of file descriptors. -/// -/// `readfds`, `writefds`, `exceptfds` must point to arrays of `FdSetElement` -/// containing at least `nfds.div_ceil(size_of::<FdSetElement>())` elements. -/// -/// If an unsupported timeout is passed, this function fails with -/// [`io::Errno::INVAL`]. -/// -/// This `select` wrapper differs from POSIX in that `nfds` is not limited to -/// `FD_SETSIZE`. Instead of using the fixed-sized `fd_set` type, this function -/// takes raw pointers to arrays of `fd_set_num_elements(max_fd + 1, num_fds)`, -/// where `max_fd` is the maximum value of any fd that will be inserted into -/// the set, and `num_fds` is the maximum number of fds that will be inserted -/// into the set. -/// -/// In particular, on Apple platforms, this function behaves as if -/// `_DARWIN_UNLIMITED_SELECT` were predefined. -/// -/// On illumos, this function is not defined because the `select` function on -/// this platform always has an `FD_SETSIZE` limitation, following POSIX. This -/// platform's documentation recommends using [`poll`] instead. -/// -/// [`fd_set_insert`], [`fd_set_remove`], and [`FdSetIter`] are provided for -/// setting, clearing, and iterating with sets. -/// -/// [`poll`]: crate::event::poll() -/// -/// # Safety -/// -/// All fds in all the sets must correspond to open file descriptors. -/// -/// # References -/// - [POSIX] -/// - [Linux] -/// - [Apple] -/// - [FreeBSD] -/// - [NetBSD] -/// - [OpenBSD] -/// - [DragonFly BSD] -/// - [Winsock] -/// - [glibc] -/// -/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/select.html -/// [Linux]: https://man7.org/linux/man-pages/man2/select.2.html -/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/select.2.html -/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=select&sektion=2 -/// [NetBSD]: https://man.netbsd.org/select.2 -/// [OpenBSD]: https://man.openbsd.org/select.2 -/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=select§ion=2 -/// [Winsock]: https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-select -/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Waiting-for-I_002fO.html#index-select -pub unsafe fn select( - nfds: i32, - readfds: Option<&mut [FdSetElement]>, - writefds: Option<&mut [FdSetElement]>, - exceptfds: Option<&mut [FdSetElement]>, - timeout: Option<&Timespec>, -) -> io::Result<i32> { - backend::event::syscalls::select(nfds, readfds, writefds, exceptfds, timeout) -} - -#[cfg(not(any(windows, target_os = "wasi")))] -const BITS: usize = size_of::<FdSetElement>() * 8; - -/// Set `fd` in the set pointed to by `fds`. -#[doc(alias = "FD_SET")] -#[inline] -pub fn fd_set_insert(fds: &mut [FdSetElement], fd: RawFd) { - #[cfg(not(any(windows, target_os = "wasi")))] - { - let fd = fd as usize; - fds[fd / BITS].0 |= 1 << (fd % BITS); - } - - #[cfg(any(windows, target_os = "wasi"))] - { - let set = unsafe { &mut *fds.as_mut_ptr().cast::<FD_SET>() }; - let fd_count = set.fd_count; - let fd_array = &set.fd_array[..fd_count as usize]; - - if !fd_array.contains(&(fd as _)) { - let fd_array = &mut set.fd_array[..fd_count as usize + 1]; - set.fd_count = fd_count + 1; - fd_array[fd_count as usize] = fd as _; - } - } -} - -/// Clear `fd` in the set pointed to by `fds`. -#[doc(alias = "FD_CLR")] -#[inline] -pub fn fd_set_remove(fds: &mut [FdSetElement], fd: RawFd) { - #[cfg(not(any(windows, target_os = "wasi")))] - { - let fd = fd as usize; - fds[fd / BITS].0 &= !(1 << (fd % BITS)); - } - - #[cfg(any(windows, target_os = "wasi"))] - { - let set = unsafe { &mut *fds.as_mut_ptr().cast::<FD_SET>() }; - let fd_count = set.fd_count; - let fd_array = &set.fd_array[..fd_count as usize]; - - if let Some(pos) = fd_array.iter().position(|p| *p as RawFd == fd) { - set.fd_count = fd_count - 1; - set.fd_array[pos] = *set.fd_array.last().unwrap(); - } - } -} - -/// Compute the minimum `nfds` value needed for the set pointed to by `fds`. -#[inline] -pub fn fd_set_bound(fds: &[FdSetElement]) -> RawFd { - #[cfg(not(any(windows, target_os = "wasi")))] - { - if let Some(position) = fds.iter().rposition(|element| element.0 != 0) { - let element = fds[position].0; - (position * BITS + (BITS - element.leading_zeros() as usize)) as RawFd - } else { - 0 - } - } - - #[cfg(any(windows, target_os = "wasi"))] - { - let set = unsafe { &*fds.as_ptr().cast::<FD_SET>() }; - let fd_count = set.fd_count; - let fd_array = &set.fd_array[..fd_count as usize]; - let mut max = 0; - for fd in fd_array { - if *fd >= max { - max = *fd + 1; - } - } - max as RawFd - } -} - -/// Compute the number of `FdSetElement`s needed to hold a set which can -/// contain up to `set_count` file descriptors with values less than `nfds`. -#[inline] -pub fn fd_set_num_elements(set_count: usize, nfds: RawFd) -> usize { - #[cfg(any(windows, target_os = "wasi"))] - { - let _ = nfds; - - fd_set_num_elements_for_fd_array(set_count) - } - - #[cfg(not(any(windows, target_os = "wasi")))] - { - let _ = set_count; - - fd_set_num_elements_for_bitvector(nfds) - } -} - -/// `fd_set_num_elements` implementation on platforms with fd array -/// implementations. -#[cfg(any(windows, target_os = "wasi"))] -#[inline] -pub(crate) fn fd_set_num_elements_for_fd_array(set_count: usize) -> usize { - // Ensure that we always have a big enough set to dereference an `FD_SET`. - core::cmp::max( - fd_set_num_elements_for_fd_array_raw(set_count), - div_ceil(size_of::<FD_SET>(), size_of::<FdSetElement>()), - ) -} - -/// Compute the raw `fd_set_num_elements` value, before ensuring the value is -/// big enough to dereference an `FD_SET`. -#[cfg(any(windows, target_os = "wasi"))] -#[inline] -fn fd_set_num_elements_for_fd_array_raw(set_count: usize) -> usize { - // Allocate space for an `fd_count` field, plus `set_count` elements - // for the `fd_array` field. - div_ceil( - core::cmp::max(align_of::<FD_SET>(), align_of::<RawFd>()) + set_count * size_of::<RawFd>(), - size_of::<FdSetElement>(), - ) -} - -/// `fd_set_num_elements` implementation on platforms with bitvector -/// implementations. -#[cfg(not(any(windows, target_os = "wasi")))] -#[inline] -pub(crate) fn fd_set_num_elements_for_bitvector(nfds: RawFd) -> usize { - // Allocate space for a dense bitvector for `nfds` bits. - let nfds = nfds as usize; - div_ceil(nfds, BITS) -} - -fn div_ceil(lhs: usize, rhs: usize) -> usize { - let d = lhs / rhs; - let r = lhs % rhs; - if r > 0 { - d + 1 - } else { - d - } -} - -/// An iterator over the fds in a set. -#[doc(alias = "FD_ISSET")] -#[cfg(not(any(windows, target_os = "wasi")))] -pub struct FdSetIter<'a> { - current: RawFd, - fds: &'a [FdSetElement], -} - -/// An iterator over the fds in a set. -#[doc(alias = "FD_ISSET")] -#[cfg(any(windows, target_os = "wasi"))] -pub struct FdSetIter<'a> { - current: usize, - fds: &'a [FdSetElement], -} - -impl<'a> FdSetIter<'a> { - /// Construct a `FdSetIter` for the given set. - pub fn new(fds: &'a [FdSetElement]) -> Self { - Self { current: 0, fds } - } -} - -#[cfg(not(any(windows, target_os = "wasi")))] -impl<'a> Iterator for FdSetIter<'a> { - type Item = RawFd; - - fn next(&mut self) -> Option<Self::Item> { - if let Some(element) = self.fds.get(self.current as usize / BITS) { - // Test whether the current element has more bits set. - let shifted = element.0 >> ((self.current as usize % BITS) as u32); - if shifted != 0 { - let fd = self.current + shifted.trailing_zeros() as RawFd; - self.current = fd + 1; - return Some(fd); - } - - // Search through the array for the next element with bits set. - if let Some(index) = self.fds[(self.current as usize / BITS) + 1..] - .iter() - .position(|element| element.0 != 0) - { - let index = index + (self.current as usize / BITS) + 1; - let element = self.fds[index].0; - let fd = (index * BITS) as RawFd + element.trailing_zeros() as RawFd; - self.current = fd + 1; - return Some(fd); - } - } - None - } -} - -#[cfg(any(windows, target_os = "wasi"))] -impl<'a> Iterator for FdSetIter<'a> { - type Item = RawFd; - - fn next(&mut self) -> Option<Self::Item> { - let current = self.current; - - let set = unsafe { &*self.fds.as_ptr().cast::<FD_SET>() }; - let fd_count = set.fd_count; - let fd_array = &set.fd_array[..fd_count as usize]; - - if current == fd_count as usize { - return None; - } - let fd = fd_array[current as usize]; - self.current = current + 1; - Some(fd as RawFd) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use core::mem::{align_of, size_of}; - - #[test] - #[cfg(any(windows, target_os = "wasi"))] - fn layouts() { - // The `FdSetElement` array should be suitably aligned. - assert_eq!(align_of::<FdSetElement>(), align_of::<FD_SET>()); - - // The layout of `FD_SET` should match our layout of a set of the same - // size. - assert_eq!( - fd_set_num_elements_for_fd_array_raw( - memoffset::span_of!(FD_SET, fd_array).len() / size_of::<RawFd>() - ) * size_of::<FdSetElement>(), - size_of::<FD_SET>() - ); - assert_eq!( - fd_set_num_elements_for_fd_array( - memoffset::span_of!(FD_SET, fd_array).len() / size_of::<RawFd>() - ) * size_of::<FdSetElement>(), - size_of::<FD_SET>() - ); - - // Don't create fd sets smaller than `FD_SET`. - assert_eq!( - fd_set_num_elements_for_fd_array(0) * size_of::<FdSetElement>(), - size_of::<FD_SET>() - ); - } - - #[test] - #[cfg(any(bsd, linux_kernel))] - fn layouts() { - use crate::backend::c; - - // The `FdSetElement` array should be suitably aligned. - assert_eq!(align_of::<FdSetElement>(), align_of::<c::fd_set>()); - - // The layout of `fd_set` should match our layout of a set of the same - // size. - assert_eq!( - fd_set_num_elements_for_bitvector(c::FD_SETSIZE as RawFd) * size_of::<FdSetElement>(), - size_of::<c::fd_set>() - ); - } -} |
