#[cfg(test)]
mod tests;
use core::num::NonZero;
use core::slice;
use core::sync::atomic::{AtomicU64, Ordering};
use std::io::{self, IoSlice, IoSliceMut};
use std::sync::atomic::AtomicUsize;
use crate::errors::{Error, ErrorKind, Result};
pub(crate) const fn align_down(n: u64, alignment: NonZero<u64>) -> u64 {
n & !alignment.get().saturating_sub(1)
}
pub(crate) fn io_vectors_from_io_slices<'slices>(
bufs: &'slices [IoSlice],
) -> (u64, &'slices [libc::iovec]) {
let byte_count = bufs.iter().map(|buf| buf.len() as u64).sum();
let local_io_vectors = unsafe { slice::from_raw_parts(bufs.as_ptr().cast(), bufs.len()) };
(byte_count, local_io_vectors)
}
pub(crate) fn io_vectors_from_io_slices_mut<'slices>(
bufs: &'slices mut [IoSliceMut],
) -> (u64, &'slices [libc::iovec]) {
let byte_count = bufs.iter().map(|buf| buf.len() as u64).sum();
let local_io_vectors = unsafe { slice::from_raw_parts(bufs.as_ptr().cast(), bufs.len()) };
(byte_count, local_io_vectors)
}
pub(crate) fn ensure_process_exists(process_id: libc::pid_t) -> Result<()> {
if unsafe { libc::kill(process_id, 0) } != -1 {
return Ok(());
}
let mut err = io::Error::last_os_error();
err = match err.raw_os_error() {
Some(libc::ESRCH) => io::Error::from(io::ErrorKind::NotFound),
Some(libc::EINVAL) => io::Error::from(io::ErrorKind::InvalidInput),
Some(libc::EPERM) => io::Error::from(io::ErrorKind::PermissionDenied),
_ => err,
};
Err(Error::from_io3(err, "kill", process_id))
}
fn get_min_system_page_size() -> Result<NonZero<u64>> {
let value = match unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) } {
-1 => return Err(Error::from(ErrorKind::UnknownPageSize)),
r => r as u64,
};
if let Some(value) = NonZero::new(value) {
if value.is_power_of_two() {
return Ok(value);
}
}
Err(Error::from(ErrorKind::InvalidPageSize(value)))
}
pub(crate) fn min_system_page_size() -> Result<NonZero<u64>> {
static VALUE: AtomicU64 = AtomicU64::new(0);
if let Some(value) = NonZero::new(VALUE.load(Ordering::Acquire)) {
return Ok(value);
}
let value = get_min_system_page_size()?;
loop {
match VALUE.compare_exchange_weak(0, value.get(), Ordering::Release, Ordering::Acquire) {
Ok(_) => break Ok(value),
Err(previous_value) => {
if let Some(previous_value) = NonZero::new(previous_value) {
break Ok(previous_value); }
}
}
}
}
fn get_system_iov_max() -> NonZero<usize> {
let value = match unsafe { libc::sysconf(libc::_SC_IOV_MAX) } {
-1 | 0 => 1,
r => r as usize,
};
unsafe { NonZero::new_unchecked(value) }
}
pub(crate) fn system_iov_max() -> NonZero<usize> {
static VALUE: AtomicUsize = AtomicUsize::new(0);
if let Some(value) = NonZero::new(VALUE.load(Ordering::Acquire)) {
return value;
}
let value = get_system_iov_max();
loop {
match VALUE.compare_exchange_weak(0, value.get(), Ordering::Release, Ordering::Acquire) {
Ok(_) => break value,
Err(previous_value) => {
if let Some(previous_value) = NonZero::new(previous_value) {
break previous_value; }
}
}
}
}