diff options
Diffstat (limited to 'vendor/rustix/src/event')
| -rw-r--r-- | vendor/rustix/src/event/eventfd.rs | 20 | ||||
| -rw-r--r-- | vendor/rustix/src/event/kqueue.rs | 449 | ||||
| -rw-r--r-- | vendor/rustix/src/event/mod.rs | 29 | ||||
| -rw-r--r-- | vendor/rustix/src/event/pause.rs | 31 | ||||
| -rw-r--r-- | vendor/rustix/src/event/poll.rs | 32 | ||||
| -rw-r--r-- | vendor/rustix/src/event/port.rs | 151 | 
6 files changed, 712 insertions, 0 deletions
diff --git a/vendor/rustix/src/event/eventfd.rs b/vendor/rustix/src/event/eventfd.rs new file mode 100644 index 0000000..a76f2cf --- /dev/null +++ b/vendor/rustix/src/event/eventfd.rs @@ -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) +} diff --git a/vendor/rustix/src/event/kqueue.rs b/vendor/rustix/src/event/kqueue.rs new file mode 100644 index 0000000..d6b7cde --- /dev/null +++ b/vendor/rustix/src/event/kqueue.rs @@ -0,0 +1,449 @@ +//! An API for interfacing with `kqueue`. + +use crate::fd::{AsFd, OwnedFd, RawFd}; +use crate::pid::Pid; +use crate::signal::Signal; +use crate::{backend, io}; + +use backend::c::{self, intptr_t, kevent as kevent_t, uintptr_t}; +use backend::event::syscalls; + +use alloc::vec::Vec; +use core::mem::zeroed; +use core::ptr::slice_from_raw_parts_mut; +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: isize) -> 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 _, 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. +                    // TODO: Strict provenance, prevent int-to-ptr cast. +                    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) -> isize { +        // On NetBSD, udata is an isize and not a pointer. +        // TODO: Strict provenance, prevent ptr-to-int cast. + +        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 { +                signal: Signal::from_raw(self.inner.ident as _).unwrap(), +                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. +        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`. +/// +/// Note: in order to receive events, make sure to allocate capacity in the +/// eventlist! Otherwise, the function will return immediately. +/// +/// # 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( +    kqueue: impl AsFd, +    changelist: &[Event], +    eventlist: &mut Vec<Event>, +    timeout: Option<Duration>, +) -> io::Result<usize> { +    let timeout = timeout.map(|timeout| backend::c::timespec { +        tv_sec: timeout.as_secs() as _, +        tv_nsec: timeout.subsec_nanos() as _, +    }); + +    // Populate the event list with events. +    eventlist.set_len(0); +    let out_slice = slice_from_raw_parts_mut(eventlist.as_mut_ptr().cast(), eventlist.capacity()); +    let res = syscalls::kevent( +        kqueue.as_fd(), +        changelist, +        &mut *out_slice, +        timeout.as_ref(), +    ) +    .map(|res| res as _); + +    // Update the event list. +    if let Ok(len) = res { +        eventlist.set_len(len); +    } + +    res +} diff --git a/vendor/rustix/src/event/mod.rs b/vendor/rustix/src/event/mod.rs new file mode 100644 index 0000000..b6b7f99 --- /dev/null +++ b/vendor/rustix/src/event/mod.rs @@ -0,0 +1,29 @@ +//! Event operations. + +#[cfg(any( +    linux_kernel, +    target_os = "freebsd", +    target_os = "illumos", +    target_os = "espidf" +))] +mod eventfd; +#[cfg(all(feature = "alloc", bsd))] +pub mod kqueue; +#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] +mod pause; +mod poll; +#[cfg(solarish)] +pub mod port; + +#[cfg(linux_kernel)] +pub use crate::backend::event::epoll; +#[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}; diff --git a/vendor/rustix/src/event/pause.rs b/vendor/rustix/src/event/pause.rs new file mode 100644 index 0000000..f191084 --- /dev/null +++ b/vendor/rustix/src/event/pause.rs @@ -0,0 +1,31 @@ +use crate::backend; + +/// `pause()` +/// +/// The POSIX `pause` interface returns an error code, but the only thing +/// `pause` does is sleep until interrupted by a signal, so it always +/// returns the same thing with the same error code, so in rustix, the +/// return value is omitted. +/// +/// # References +///  - [POSIX] +///  - [Linux] +///  - [Apple] +///  - [FreeBSD] +///  - [NetBSD] +///  - [OpenBSD] +///  - [DragonFly BSD] +///  - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/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 new file mode 100644 index 0000000..30e6a4b --- /dev/null +++ b/vendor/rustix/src/event/poll.rs @@ -0,0 +1,32 @@ +use crate::{backend, io}; + +pub use backend::event::poll_fd::{PollFd, PollFlags}; + +/// `poll(self.fds, timeout)` +/// +/// # 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/9699919799/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: i32) -> 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 new file mode 100644 index 0000000..39fe5ac --- /dev/null +++ b/vendor/rustix/src/event/port.rs @@ -0,0 +1,151 @@ +//! Solaris/illumos event ports. + +use crate::backend::c; +use crate::backend::event::syscalls; +use crate::fd::{AsFd, AsRawFd, OwnedFd}; +use crate::io; + +use super::PollFlags; + +use core::time::Duration; + +/// The structure representing a port event. +#[repr(transparent)] +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 c::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 +pub fn port_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 `port_dissociate_fd`. +/// +/// # References +///  - [OpenSolaris] +///  - [illumos] +/// +/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_associate/ +/// [illumos]: https://illumos.org/man/3C/port_associate +pub unsafe fn port_associate_fd( +    port: impl AsFd, +    object: impl AsRawFd, +    events: PollFlags, +    userdata: *mut c::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 [`port_associate_fd`]. +/// +/// # References +///  - [OpenSolaris] +///  - [illumos] +/// +/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_dissociate +/// [illumos]: https://illumos.org/man/3C/port_dissociate +pub unsafe fn port_dissociate_fd(port: impl AsFd, object: impl AsRawFd) -> 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. +/// +/// # References +///  - [OpenSolaris] +///  - [illumos] +/// +/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_get/ +/// [illumos]: https://illumos.org/man/3C/port_get +pub fn port_get(port: impl AsFd, timeout: Option<Duration>) -> io::Result<Event> { +    let mut timeout = timeout.map(|timeout| c::timespec { +        tv_sec: timeout.as_secs().try_into().unwrap(), +        tv_nsec: timeout.subsec_nanos() as _, +    }); + +    syscalls::port_get(port.as_fd(), timeout.as_mut()) +} + +/// `port_getn(port, events, min_events, timeout)`—Gets multiple events from a +/// port. +/// +/// # References +///  - [OpenSolaris] +///  - [illumos] +/// +/// [OpenSolaris]: https://www.unix.com/man-page/opensolaris/3C/port_getn/ +/// [illumos]: https://illumos.org/man/3C/port_getn +#[cfg(feature = "alloc")] +pub fn port_getn( +    port: impl AsFd, +    events: &mut Vec<Event>, +    min_events: usize, +    timeout: Option<Duration>, +) -> io::Result<()> { +    events.clear(); + +    let mut timeout = timeout.map(|timeout| c::timespec { +        tv_sec: timeout.as_secs().try_into().unwrap(), +        tv_nsec: timeout.subsec_nanos() as _, +    }); + +    syscalls::port_getn( +        port.as_fd(), +        timeout.as_mut(), +        events, +        min_events.try_into().unwrap(), +    ) +} + +/// `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 +pub fn port_send(port: impl AsFd, events: i32, userdata: *mut c::c_void) -> io::Result<()> { +    syscalls::port_send(port.as_fd(), events, userdata.cast()) +}  | 
