summaryrefslogtreecommitdiffstats
path: root/vendor/rustix/src/backend/libc/event
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/rustix/src/backend/libc/event')
-rw-r--r--vendor/rustix/src/backend/libc/event/epoll.rs486
-rw-r--r--vendor/rustix/src/backend/libc/event/mod.rs9
-rw-r--r--vendor/rustix/src/backend/libc/event/poll_fd.rs137
-rw-r--r--vendor/rustix/src/backend/libc/event/syscalls.rs161
-rw-r--r--vendor/rustix/src/backend/libc/event/types.rs19
-rw-r--r--vendor/rustix/src/backend/libc/event/windows_syscalls.rs16
6 files changed, 828 insertions, 0 deletions
diff --git a/vendor/rustix/src/backend/libc/event/epoll.rs b/vendor/rustix/src/backend/libc/event/epoll.rs
new file mode 100644
index 000000000..c59a38cd4
--- /dev/null
+++ b/vendor/rustix/src/backend/libc/event/epoll.rs
@@ -0,0 +1,486 @@
+//! epoll support.
+//!
+//! This is an experiment, and it isn't yet clear whether epoll is the right
+//! level of abstraction at which to introduce safety. But it works fairly well
+//! in simple examples 🙂.
+//!
+//! # Examples
+//!
+//! ```no_run
+//! # #[cfg(feature = "net")]
+//! # fn main() -> std::io::Result<()> {
+//! use rustix::event::epoll;
+//! use rustix::fd::AsFd;
+//! use rustix::io::{ioctl_fionbio, read, write};
+//! use rustix::net::{
+//! accept, bind_v4, 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_v4(&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 = epoll::EventVec::with_capacity(4);
+//! loop {
+//! epoll::wait(&epoll, &mut event_list, -1)?;
+//! for event in &event_list {
+//! 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() {}
+//! ```
+
+use crate::backend::c;
+use crate::backend::conv::{ret, ret_owned_fd, ret_u32};
+use crate::fd::{AsFd, AsRawFd, OwnedFd};
+use crate::io;
+use crate::utils::as_mut_ptr;
+use alloc::vec::Vec;
+use bitflags::bitflags;
+use core::ffi::c_void;
+use core::hash::{Hash, Hasher};
+use core::ptr::null_mut;
+use core::slice;
+
+bitflags! {
+ /// `EPOLL_*` for use with [`new`].
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct CreateFlags: u32 {
+ /// `EPOLL_CLOEXEC`
+ const CLOEXEC = bitcast!(c::EPOLL_CLOEXEC);
+ }
+}
+
+bitflags! {
+ /// `EPOLL*` for use with [`add`].
+ #[repr(transparent)]
+ #[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct EventFlags: u32 {
+ /// `EPOLLIN`
+ const IN = bitcast!(c::EPOLLIN);
+
+ /// `EPOLLOUT`
+ const OUT = bitcast!(c::EPOLLOUT);
+
+ /// `EPOLLPRI`
+ const PRI = bitcast!(c::EPOLLPRI);
+
+ /// `EPOLLERR`
+ const ERR = bitcast!(c::EPOLLERR);
+
+ /// `EPOLLHUP`
+ const HUP = bitcast!(c::EPOLLHUP);
+
+ /// `EPOLLRDNORM`
+ const RDNORM = bitcast!(c::EPOLLRDNORM);
+
+ /// `EPOLLRDBAND`
+ const RDBAND = bitcast!(c::EPOLLRDBAND);
+
+ /// `EPOLLWRNORM`
+ const WRNORM = bitcast!(c::EPOLLWRNORM);
+
+ /// `EPOLLWRBAND`
+ const WRBAND = bitcast!(c::EPOLLWRBAND);
+
+ /// `EPOLLMSG`
+ const MSG = bitcast!(c::EPOLLMSG);
+
+ /// `EPOLLRDHUP`
+ const RDHUP = bitcast!(c::EPOLLRDHUP);
+
+ /// `EPOLLET`
+ const ET = bitcast!(c::EPOLLET);
+
+ /// `EPOLLONESHOT`
+ const ONESHOT = bitcast!(c::EPOLLONESHOT);
+
+ /// `EPOLLWAKEUP`
+ const WAKEUP = bitcast!(c::EPOLLWAKEUP);
+
+ /// `EPOLLEXCLUSIVE`
+ #[cfg(not(target_os = "android"))]
+ const EXCLUSIVE = bitcast!(c::EPOLLEXCLUSIVE);
+ }
+}
+
+/// `epoll_create1(flags)`—Creates a new epoll object.
+///
+/// Use the [`CreateFlags::CLOEXEC`] flag to prevent the resulting file
+/// descriptor from being implicitly passed across `exec` boundaries.
+#[inline]
+#[doc(alias = "epoll_create1")]
+pub fn create(flags: CreateFlags) -> io::Result<OwnedFd> {
+ // SAFETY: We're calling `epoll_create1` via FFI and we know how it
+ // behaves.
+ unsafe { ret_owned_fd(c::epoll_create1(bitflags_bits!(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 `events` occurring
+/// on the file descriptor associated with `data`.
+///
+/// If [`delete`] is not called on the I/O source passed into this function
+/// before the I/O source is `close`d, then the `epoll` will act as if the I/O
+/// source is still registered with it. This can lead to spurious events being
+/// returned from [`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.
+#[doc(alias = "epoll_ctl")]
+pub fn add(
+ epoll: impl AsFd,
+ source: impl AsFd,
+ data: EventData,
+ event_flags: EventFlags,
+) -> io::Result<()> {
+ // SAFETY: We're calling `epoll_ctl` via FFI and we know how it
+ // behaves. We use our own `Event` struct instead of libc's because
+ // ours preserves pointer provenance instead of just using a `u64`,
+ // and we have tests elsehwere for layout equivalence.
+ unsafe {
+ let raw_fd = source.as_fd().as_raw_fd();
+ ret(c::epoll_ctl(
+ epoll.as_fd().as_raw_fd(),
+ c::EPOLL_CTL_ADD,
+ raw_fd,
+ as_mut_ptr(&mut Event {
+ flags: event_flags,
+ data,
+ })
+ .cast(),
+ ))
+ }
+}
+
+/// `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`.
+#[doc(alias = "epoll_ctl")]
+pub fn modify(
+ epoll: impl AsFd,
+ source: impl AsFd,
+ data: EventData,
+ event_flags: EventFlags,
+) -> io::Result<()> {
+ let raw_fd = source.as_fd().as_raw_fd();
+
+ // SAFETY: We're calling `epoll_ctl` via FFI and we know how it
+ // behaves. We use our own `Event` struct instead of libc's because
+ // ours preserves pointer provenance instead of just using a `u64`,
+ // and we have tests elsehwere for layout equivalence.
+ unsafe {
+ ret(c::epoll_ctl(
+ epoll.as_fd().as_raw_fd(),
+ c::EPOLL_CTL_MOD,
+ raw_fd,
+ as_mut_ptr(&mut Event {
+ flags: event_flags,
+ data,
+ })
+ .cast(),
+ ))
+ }
+}
+
+/// `epoll_ctl(self, EPOLL_CTL_DEL, target, NULL)`—Removes an element in
+/// a given epoll object.
+#[doc(alias = "epoll_ctl")]
+pub fn delete(epoll: impl AsFd, source: impl AsFd) -> io::Result<()> {
+ // SAFETY: We're calling `epoll_ctl` via FFI and we know how it
+ // behaves.
+ unsafe {
+ let raw_fd = source.as_fd().as_raw_fd();
+ ret(c::epoll_ctl(
+ epoll.as_fd().as_raw_fd(),
+ c::EPOLL_CTL_DEL,
+ raw_fd,
+ null_mut(),
+ ))
+ }
+}
+
+/// `epoll_wait(self, events, timeout)`—Waits for registered events of
+/// interest.
+///
+/// For each event of interest, an element is written to `events`. On
+/// success, this returns the number of written elements.
+pub fn wait(epoll: impl AsFd, event_list: &mut EventVec, timeout: c::c_int) -> io::Result<()> {
+ // SAFETY: We're calling `epoll_wait` via FFI and we know how it
+ // behaves.
+ unsafe {
+ event_list.events.set_len(0);
+ let nfds = ret_u32(c::epoll_wait(
+ epoll.as_fd().as_raw_fd(),
+ event_list.events.as_mut_ptr().cast::<c::epoll_event>(),
+ event_list.events.capacity().try_into().unwrap_or(i32::MAX),
+ timeout,
+ ))?;
+ event_list.events.set_len(nfds as usize);
+ }
+
+ Ok(())
+}
+
+/// An iterator over the `Event`s in an `EventVec`.
+pub struct Iter<'a> {
+ /// Use `Copied` to copy the struct, since `Event` is `packed` on some
+ /// platforms, and it's common for users to directly destructure it,
+ /// which would lead to errors about forming references to packed fields.
+ iter: core::iter::Copied<slice::Iter<'a, Event>>,
+}
+
+impl<'a> Iterator for Iter<'a> {
+ type Item = Event;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next()
+ }
+}
+
+/// A record of an event that occurred.
+#[repr(C)]
+#[cfg_attr(
+ any(
+ all(
+ target_arch = "x86",
+ not(target_env = "musl"),
+ not(target_os = "android"),
+ ),
+ target_arch = "x86_64",
+ ),
+ repr(packed)
+)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+pub struct Event {
+ /// Which specific event(s) occurred.
+ pub flags: EventFlags,
+ /// User data.
+ pub data: EventData,
+}
+
+/// Data assocated with an [`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,
+}
+
+/// A vector of `Event`s, plus context for interpreting them.
+pub struct EventVec {
+ events: Vec<Event>,
+}
+
+impl EventVec {
+ /// Constructs an `EventVec` from raw pointer, length, and capacity.
+ ///
+ /// # Safety
+ ///
+ /// This function calls [`Vec::from_raw_parts`] with its arguments.
+ ///
+ /// [`Vec::from_raw_parts`]: https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.from_raw_parts
+ #[inline]
+ pub unsafe fn from_raw_parts(ptr: *mut Event, len: usize, capacity: usize) -> Self {
+ Self {
+ events: Vec::from_raw_parts(ptr, len, capacity),
+ }
+ }
+
+ /// Constructs an `EventVec` with memory for `capacity` `Event`s.
+ #[inline]
+ pub fn with_capacity(capacity: usize) -> Self {
+ Self {
+ events: Vec::with_capacity(capacity),
+ }
+ }
+
+ /// Returns the current `Event` capacity of this `EventVec`.
+ #[inline]
+ pub fn capacity(&self) -> usize {
+ self.events.capacity()
+ }
+
+ /// Reserves enough memory for at least `additional` more `Event`s.
+ #[inline]
+ pub fn reserve(&mut self, additional: usize) {
+ self.events.reserve(additional);
+ }
+
+ /// Reserves enough memory for exactly `additional` more `Event`s.
+ #[inline]
+ pub fn reserve_exact(&mut self, additional: usize) {
+ self.events.reserve_exact(additional);
+ }
+
+ /// Clears all the `Events` out of this `EventVec`.
+ #[inline]
+ pub fn clear(&mut self) {
+ self.events.clear();
+ }
+
+ /// Shrinks the capacity of this `EventVec` as much as possible.
+ #[inline]
+ pub fn shrink_to_fit(&mut self) {
+ self.events.shrink_to_fit();
+ }
+
+ /// Returns an iterator over the `Event`s in this `EventVec`.
+ #[inline]
+ pub fn iter(&self) -> Iter<'_> {
+ Iter {
+ iter: self.events.iter().copied(),
+ }
+ }
+
+ /// Returns the number of `Event`s logically contained in this `EventVec`.
+ #[inline]
+ pub fn len(&mut self) -> usize {
+ self.events.len()
+ }
+
+ /// Tests whether this `EventVec` is logically empty.
+ #[inline]
+ pub fn is_empty(&mut self) -> bool {
+ self.events.is_empty()
+ }
+}
+
+impl<'a> IntoIterator for &'a EventVec {
+ type IntoIter = Iter<'a>;
+ type Item = Event;
+
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+}
+
+#[test]
+fn test_epoll_layouts() {
+ check_renamed_type!(Event, epoll_event);
+ check_renamed_type!(Event, epoll_event);
+ check_renamed_struct_renamed_field!(Event, epoll_event, flags, events);
+ check_renamed_struct_renamed_field!(Event, epoll_event, data, u64);
+}
diff --git a/vendor/rustix/src/backend/libc/event/mod.rs b/vendor/rustix/src/backend/libc/event/mod.rs
new file mode 100644
index 000000000..6aed4612a
--- /dev/null
+++ b/vendor/rustix/src/backend/libc/event/mod.rs
@@ -0,0 +1,9 @@
+pub(crate) mod poll_fd;
+#[cfg(not(windows))]
+pub(crate) mod types;
+
+#[cfg_attr(windows, path = "windows_syscalls.rs")]
+pub(crate) mod syscalls;
+
+#[cfg(linux_kernel)]
+pub mod epoll;
diff --git a/vendor/rustix/src/backend/libc/event/poll_fd.rs b/vendor/rustix/src/backend/libc/event/poll_fd.rs
new file mode 100644
index 000000000..49a6d1126
--- /dev/null
+++ b/vendor/rustix/src/backend/libc/event/poll_fd.rs
@@ -0,0 +1,137 @@
+use crate::backend::c;
+use crate::backend::conv::borrowed_fd;
+use crate::backend::fd::{AsFd, AsRawFd, BorrowedFd, LibcFd};
+use bitflags::bitflags;
+use core::marker::PhantomData;
+#[cfg(windows)]
+use {
+ crate::backend::fd::{AsSocket, RawFd},
+ core::fmt,
+};
+
+bitflags! {
+ /// `POLL*` flags for use with [`poll`].
+ ///
+ /// [`poll`]: crate::io::poll
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct PollFlags: c::c_short {
+ /// `POLLIN`
+ const IN = c::POLLIN;
+ /// `POLLPRI`
+ #[cfg(not(target_os = "wasi"))]
+ const PRI = c::POLLPRI;
+ /// `POLLOUT`
+ const OUT = c::POLLOUT;
+ /// `POLLRDNORM`
+ const RDNORM = c::POLLRDNORM;
+ /// `POLLWRNORM`
+ const WRNORM = c::POLLWRNORM;
+ /// `POLLRDBAND`
+ #[cfg(not(target_os = "wasi"))]
+ const RDBAND = c::POLLRDBAND;
+ /// `POLLWRBAND`
+ #[cfg(not(target_os = "wasi"))]
+ const WRBAND = c::POLLWRBAND;
+ /// `POLLERR`
+ const ERR = c::POLLERR;
+ /// `POLLHUP`
+ const HUP = c::POLLHUP;
+ /// `POLLNVAL`
+ const NVAL = c::POLLNVAL;
+ /// `POLLRDHUP`
+ #[cfg(all(
+ linux_kernel,
+ not(any(target_arch = "sparc", target_arch = "sparc64"))),
+ )]
+ const RDHUP = c::POLLRDHUP;
+ }
+}
+
+/// `struct pollfd`—File descriptor and flags for use with [`poll`].
+///
+/// [`poll`]: crate::event::poll
+#[doc(alias = "pollfd")]
+#[derive(Clone)]
+#[cfg_attr(not(windows), derive(Debug))]
+#[repr(transparent)]
+pub struct PollFd<'fd> {
+ pollfd: c::pollfd,
+ _phantom: PhantomData<BorrowedFd<'fd>>,
+}
+
+#[cfg(windows)]
+impl<'fd> fmt::Debug for PollFd<'fd> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_struct("pollfd")
+ .field("fd", &self.pollfd.fd)
+ .field("events", &self.pollfd.events)
+ .field("revents", &self.pollfd.revents)
+ .finish()
+ }
+}
+
+impl<'fd> PollFd<'fd> {
+ /// Constructs a new `PollFd` holding `fd` and `events`.
+ #[inline]
+ pub fn new<Fd: AsFd>(fd: &'fd Fd, events: PollFlags) -> Self {
+ Self::from_borrowed_fd(fd.as_fd(), events)
+ }
+
+ /// Sets the contained file descriptor to `fd`.
+ #[inline]
+ pub fn set_fd<Fd: AsFd>(&mut self, fd: &'fd Fd) {
+ self.pollfd.fd = fd.as_fd().as_raw_fd() as LibcFd;
+ }
+
+ /// Clears the ready events.
+ #[inline]
+ pub fn clear_revents(&mut self) {
+ self.pollfd.revents = 0;
+ }
+
+ /// Constructs a new `PollFd` holding `fd` and `events`.
+ ///
+ /// This is the same as `new`, but can be used to avoid borrowing the
+ /// `BorrowedFd`, which can be tricky in situations where the `BorrowedFd`
+ /// is a temporary.
+ #[inline]
+ pub fn from_borrowed_fd(fd: BorrowedFd<'fd>, events: PollFlags) -> Self {
+ Self {
+ pollfd: c::pollfd {
+ fd: borrowed_fd(fd),
+ events: events.bits(),
+ revents: 0,
+ },
+ _phantom: PhantomData,
+ }
+ }
+
+ /// Returns the ready events.
+ #[inline]
+ pub fn revents(&self) -> PollFlags {
+ // Use `unwrap()` here because in theory we know we know all the bits
+ // the OS might set here, but OS's have added extensions in the past.
+ PollFlags::from_bits(self.pollfd.revents).unwrap()
+ }
+}
+
+#[cfg(not(windows))]
+impl<'fd> AsFd for PollFd<'fd> {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ // SAFETY: Our constructors and `set_fd` require `pollfd.fd` to be
+ // valid for the `fd lifetime.
+ unsafe { BorrowedFd::borrow_raw(self.pollfd.fd) }
+ }
+}
+
+#[cfg(windows)]
+impl<'fd> AsSocket for PollFd<'fd> {
+ #[inline]
+ fn as_socket(&self) -> BorrowedFd<'_> {
+ // SAFETY: Our constructors and `set_fd` require `pollfd.fd` to be
+ // valid for the `fd lifetime.
+ unsafe { BorrowedFd::borrow_raw(self.pollfd.fd as RawFd) }
+ }
+}
diff --git a/vendor/rustix/src/backend/libc/event/syscalls.rs b/vendor/rustix/src/backend/libc/event/syscalls.rs
new file mode 100644
index 000000000..11f6af83e
--- /dev/null
+++ b/vendor/rustix/src/backend/libc/event/syscalls.rs
@@ -0,0 +1,161 @@
+//! libc syscalls supporting `rustix::event`.
+
+use crate::backend::c;
+use crate::backend::conv::ret_c_int;
+#[cfg(any(apple, netbsdlike, target_os = "dragonfly", target_os = "solaris"))]
+use crate::backend::conv::ret_owned_fd;
+use crate::event::PollFd;
+#[cfg(any(linux_kernel, bsd, solarish))]
+use crate::fd::OwnedFd;
+use crate::io;
+#[cfg(any(bsd, solarish))]
+use {crate::backend::conv::borrowed_fd, crate::fd::BorrowedFd, core::mem::MaybeUninit};
+#[cfg(solarish)]
+use {
+ crate::backend::conv::ret, crate::event::port::Event, crate::utils::as_mut_ptr,
+ core::ptr::null_mut,
+};
+#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "illumos"))]
+use {crate::backend::conv::ret_owned_fd, crate::event::EventfdFlags};
+#[cfg(bsd)]
+use {crate::event::kqueue::Event, crate::utils::as_ptr, core::ptr::null};
+
+#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "illumos"))]
+pub(crate) fn eventfd(initval: u32, flags: EventfdFlags) -> io::Result<OwnedFd> {
+ #[cfg(linux_kernel)]
+ unsafe {
+ syscall! {
+ fn eventfd2(
+ initval: c::c_uint,
+ flags: c::c_int
+ ) via SYS_eventfd2 -> c::c_int
+ }
+ ret_owned_fd(eventfd2(initval, bitflags_bits!(flags)))
+ }
+
+ #[cfg(any(target_os = "freebsd", target_os = "illumos"))]
+ unsafe {
+ ret_owned_fd(c::eventfd(initval, bitflags_bits!(flags)))
+ }
+}
+
+#[cfg(bsd)]
+pub(crate) fn kqueue() -> io::Result<OwnedFd> {
+ unsafe { ret_owned_fd(c::kqueue()) }
+}
+
+#[cfg(bsd)]
+pub(crate) unsafe fn kevent(
+ kq: BorrowedFd<'_>,
+ changelist: &[Event],
+ eventlist: &mut [MaybeUninit<Event>],
+ timeout: Option<&c::timespec>,
+) -> io::Result<c::c_int> {
+ ret_c_int(c::kevent(
+ borrowed_fd(kq),
+ changelist.as_ptr().cast(),
+ changelist
+ .len()
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ eventlist.as_mut_ptr().cast(),
+ eventlist
+ .len()
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ timeout.map_or(null(), as_ptr),
+ ))
+}
+
+#[inline]
+pub(crate) fn poll(fds: &mut [PollFd<'_>], timeout: c::c_int) -> io::Result<usize> {
+ let nfds = fds
+ .len()
+ .try_into()
+ .map_err(|_convert_err| io::Errno::INVAL)?;
+
+ ret_c_int(unsafe { c::poll(fds.as_mut_ptr().cast(), nfds, timeout) })
+ .map(|nready| nready as usize)
+}
+
+#[cfg(solarish)]
+pub(crate) fn port_create() -> io::Result<OwnedFd> {
+ unsafe { ret_owned_fd(c::port_create()) }
+}
+
+#[cfg(solarish)]
+pub(crate) unsafe fn port_associate(
+ port: BorrowedFd<'_>,
+ source: c::c_int,
+ object: c::uintptr_t,
+ events: c::c_int,
+ user: *mut c::c_void,
+) -> io::Result<()> {
+ ret(c::port_associate(
+ borrowed_fd(port),
+ source,
+ object,
+ events,
+ user,
+ ))
+}
+
+#[cfg(solarish)]
+pub(crate) unsafe fn port_dissociate(
+ port: BorrowedFd<'_>,
+ source: c::c_int,
+ object: c::uintptr_t,
+) -> io::Result<()> {
+ ret(c::port_dissociate(borrowed_fd(port), source, object))
+}
+
+#[cfg(solarish)]
+pub(crate) fn port_get(
+ port: BorrowedFd<'_>,
+ timeout: Option<&mut c::timespec>,
+) -> io::Result<Event> {
+ let mut event = MaybeUninit::<c::port_event>::uninit();
+ let timeout = timeout.map_or(null_mut(), as_mut_ptr);
+
+ unsafe {
+ ret(c::port_get(borrowed_fd(port), event.as_mut_ptr(), timeout))?;
+ }
+
+ // If we're done, initialize the event and return it.
+ Ok(Event(unsafe { event.assume_init() }))
+}
+
+#[cfg(solarish)]
+pub(crate) fn port_getn(
+ port: BorrowedFd<'_>,
+ timeout: Option<&mut c::timespec>,
+ events: &mut Vec<Event>,
+ mut nget: u32,
+) -> io::Result<()> {
+ let timeout = timeout.map_or(null_mut(), as_mut_ptr);
+ unsafe {
+ ret(c::port_getn(
+ borrowed_fd(port),
+ events.as_mut_ptr().cast(),
+ events.len().try_into().unwrap(),
+ &mut nget,
+ timeout,
+ ))?;
+ }
+
+ // Update the vector length.
+ unsafe {
+ events.set_len(nget.try_into().unwrap());
+ }
+
+ Ok(())
+}
+
+#[cfg(solarish)]
+pub(crate) fn port_send(
+ port: BorrowedFd<'_>,
+ events: c::c_int,
+ userdata: *mut c::c_void,
+) -> io::Result<()> {
+ unsafe { ret(c::port_send(borrowed_fd(port), events, userdata)) }
+}
diff --git a/vendor/rustix/src/backend/libc/event/types.rs b/vendor/rustix/src/backend/libc/event/types.rs
new file mode 100644
index 000000000..632b1be63
--- /dev/null
+++ b/vendor/rustix/src/backend/libc/event/types.rs
@@ -0,0 +1,19 @@
+#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "illumos"))]
+use {crate::backend::c, bitflags::bitflags};
+
+#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "illumos"))]
+bitflags! {
+ /// `EFD_*` flags for use with [`eventfd`].
+ ///
+ /// [`eventfd`]: crate::io::eventfd
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct EventfdFlags: u32 {
+ /// `EFD_CLOEXEC`
+ const CLOEXEC = bitcast!(c::EFD_CLOEXEC);
+ /// `EFD_NONBLOCK`
+ const NONBLOCK = bitcast!(c::EFD_NONBLOCK);
+ /// `EFD_SEMAPHORE`
+ const SEMAPHORE = bitcast!(c::EFD_SEMAPHORE);
+ }
+}
diff --git a/vendor/rustix/src/backend/libc/event/windows_syscalls.rs b/vendor/rustix/src/backend/libc/event/windows_syscalls.rs
new file mode 100644
index 000000000..8ccad4794
--- /dev/null
+++ b/vendor/rustix/src/backend/libc/event/windows_syscalls.rs
@@ -0,0 +1,16 @@
+//! Windows system calls in the `event` module.
+
+use crate::backend::c;
+use crate::backend::conv::ret_c_int;
+use crate::event::PollFd;
+use crate::io;
+
+pub(crate) fn poll(fds: &mut [PollFd<'_>], timeout: c::c_int) -> io::Result<usize> {
+ let nfds = fds
+ .len()
+ .try_into()
+ .map_err(|_convert_err| io::Errno::INVAL)?;
+
+ ret_c_int(unsafe { c::poll(fds.as_mut_ptr().cast(), nfds, timeout) })
+ .map(|nready| nready as usize)
+}