diff options
Diffstat (limited to 'vendor/rustix/src/event/select.rs')
| -rw-r--r-- | vendor/rustix/src/event/select.rs | 391 |
1 files changed, 0 insertions, 391 deletions
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>() - ); - } -} |
