Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

347
vendor/rustix/src/event/epoll.rs vendored Normal file
View File

@@ -0,0 +1,347 @@
//! 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);
}
}

20
vendor/rustix/src/event/eventfd.rs vendored Normal file
View File

@@ -0,0 +1,20 @@
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)
}

466
vendor/rustix/src/event/kqueue.rs vendored Normal file
View File

@@ -0,0 +1,466 @@
//! 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&section=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&section=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())
}

34
vendor/rustix/src/event/mod.rs vendored Normal file
View File

@@ -0,0 +1,34 @@
//! 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::*;

31
vendor/rustix/src/event/pause.rs vendored Normal file
View File

@@ -0,0 +1,31 @@
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&section=3
/// [illumos]: https://illumos.org/man/2/pause
#[inline]
pub fn pause() {
backend::event::syscalls::pause()
}

47
vendor/rustix/src/event/poll.rs vendored Normal file
View File

@@ -0,0 +1,47 @@
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&section=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)
}

197
vendor/rustix/src/event/port.rs vendored Normal file
View File

@@ -0,0 +1,197 @@
//! 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())
}

391
vendor/rustix/src/event/select.rs vendored Normal file
View File

@@ -0,0 +1,391 @@
//! 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&section=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>()
);
}
}