use super::Page;
use core::ffi::c_void;
use core::ptr::NonNull;
pub fn page_size() -> usize {
rustix::param::page_size()
}
#[derive(Debug, Clone, thiserror::Error)]
pub enum PageAllocError {
#[error("could not map a memory page: {0}")]
Mmap(rustix::io::Errno),
#[error("could not lock memory page: {0}")]
Mlock(rustix::io::Errno),
}
impl Page {
fn as_c_ptr_mut(&self) -> *mut c_void {
self.as_ptr_mut() as *mut c_void
}
fn alloc_new_noreserve() -> Result<Self, rustix::io::Errno> {
use rustix::mm::{MapFlags, ProtFlags};
let addr: *mut c_void = core::ptr::null_mut();
let page_size = page_size();
let prot = ProtFlags::READ | ProtFlags::WRITE;
cfg_if::cfg_if! {
if #[cfg(target_os = "redox")] {
let flags = MapFlags::PRIVATE;
} else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] {
let flags = MapFlags::PRIVATE | MapFlags::NOCORE;
} else {
let flags = MapFlags::PRIVATE | MapFlags::NORESERVE;
}
}
let page_ptr: *mut c_void =
unsafe { rustix::mm::mmap_anonymous(addr, page_size, prot, flags) }?;
let page_ptr = unsafe { NonNull::new_unchecked(page_ptr as *mut u8) };
Ok(Self {
page_ptr,
page_size,
_phantom_pagemem: core::marker::PhantomData,
})
}
fn mlock(&mut self) -> Result<(), rustix::io::Errno> {
unsafe { rustix::mm::mlock(self.as_c_ptr_mut(), self.page_size()) }
}
pub fn alloc_new_lock() -> Result<Self, PageAllocError> {
let mut page = Self::alloc_new_noreserve().map_err(PageAllocError::Mmap)?;
page.mlock().map_err(PageAllocError::Mlock)?;
Ok(page)
}
}
impl Drop for Page {
fn drop(&mut self) {
let ptr = self.as_c_ptr_mut();
unsafe {
rustix::mm::munmap(ptr, self.page_size()).unwrap();
}
}
}