mod enter;
pub(in crate::backend::uring) mod fixed;
pub(in crate::backend::uring) mod pipe;
mod provided;
pub(in crate::backend::uring) mod recvmsg;
use std::{io, iter, mem};
pub(in crate::backend::uring) use enter::RegisteredEnter;
pub(in crate::backend::uring) use provided::{Buffer, CanaryRing, ProvidedRing};
use crate::platform;
pub(in crate::backend::uring) struct Entropy([u64; 2]);
#[repr(transparent)]
pub(crate) struct Cpu(u16);
pub(crate) struct Cpus {
mask: libc::cpu_set_t,
front: u16,
back: u16,
remaining: u16,
}
impl Entropy {
pub(in crate::backend::uring) fn acquire() -> io::Result<Self> {
let mut words = mem::MaybeUninit::<[u64; 2]>::uninit();
let mut data = words.as_mut_ptr().cast::<u8>();
let mut len = mem::size_of::<[u64; 2]>();
while len != 0 {
let written = unsafe { libc::getrandom(data.cast(), len, 0) };
if written < 0 {
let error = io::Error::last_os_error();
if error.kind() == io::ErrorKind::Interrupted {
continue;
}
return Err(error);
}
if written == 0 {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"kernel entropy returned no bytes",
));
}
let written = written as usize;
data = unsafe { data.add(written) };
len -= written;
}
Ok(Self(unsafe { words.assume_init() }))
}
pub(in crate::backend::uring) const fn into_words(self) -> [u64; 2] {
self.0
}
}
impl platform::Bound for Cpu {
fn bind(raw: u16) -> io::Result<Self> {
if raw >= libc::CPU_SETSIZE as u16 {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"dope: cpu index exceeds CPU_SETSIZE",
));
}
let mut mask: libc::cpu_set_t = unsafe { mem::zeroed() };
unsafe { libc::CPU_SET(usize::from(raw), &mut mask) };
let result =
unsafe { libc::sched_setaffinity(0, mem::size_of::<libc::cpu_set_t>(), &mask) };
if result != 0 {
let error = io::Error::last_os_error();
return Err(io::Error::new(
error.kind(),
format!("failed to pin current thread to CPU {raw}"),
));
}
Ok(Self(raw))
}
fn cpu(&self) -> u16 {
self.0
}
}
impl platform::Available for Cpus {
fn current() -> io::Result<Self> {
const LIMIT: u16 = libc::CPU_SETSIZE as u16;
const _: () = assert!((libc::CPU_SETSIZE as usize) <= u16::MAX as usize);
let mut mask: libc::cpu_set_t = unsafe { mem::zeroed() };
let result =
unsafe { libc::sched_getaffinity(0, mem::size_of::<libc::cpu_set_t>(), &mut mask) };
if result != 0 {
return Err(io::Error::last_os_error());
}
let remaining = (0..LIMIT)
.filter(|cpu| unsafe { libc::CPU_ISSET(usize::from(*cpu), &mask) })
.count() as u16;
Ok(Self {
mask,
front: 0,
back: LIMIT,
remaining,
})
}
}
impl Cpus {
fn contains(&self, cpu: u16) -> bool {
unsafe { libc::CPU_ISSET(usize::from(cpu), &self.mask) }
}
}
impl Iterator for Cpus {
type Item = u16;
fn next(&mut self) -> Option<Self::Item> {
while self.front < self.back {
let cpu = self.front;
self.front += 1;
if self.contains(cpu) {
self.remaining -= 1;
return Some(cpu);
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = usize::from(self.remaining);
(remaining, Some(remaining))
}
}
impl DoubleEndedIterator for Cpus {
fn next_back(&mut self) -> Option<Self::Item> {
while self.front < self.back {
self.back -= 1;
let cpu = self.back;
if self.contains(cpu) {
self.remaining -= 1;
return Some(cpu);
}
}
None
}
}
impl ExactSizeIterator for Cpus {}
impl iter::FusedIterator for Cpus {}