use std::ptr::NonNull;
use libc::{mmap, munmap, MAP_ANONYMOUS, MAP_PRIVATE, MAP_HUGETLB, MAP_POPULATE, PROT_READ, PROT_WRITE};
pub struct HugePageBuffer {
ptr: NonNull<u8>,
capacity: usize,
}
unsafe impl Send for HugePageBuffer {}
unsafe impl Sync for HugePageBuffer {}
impl HugePageBuffer {
pub fn new(capacity: usize) -> Result<Self, std::io::Error> {
let hugepage_size = 2 * 1024 * 1024;
let aligned_capacity = (capacity + hugepage_size - 1) & !(hugepage_size - 1);
let flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE;
let ptr = unsafe {
mmap(
std::ptr::null_mut(),
aligned_capacity,
PROT_READ | PROT_WRITE,
flags,
-1,
0,
)
};
if ptr == libc::MAP_FAILED {
return Err(std::io::Error::last_os_error());
}
let non_null_ptr = NonNull::new(ptr as *mut u8)
.ok_or_else(|| std::io::Error::new(std::io::ErrorKind::Other, "MAP_FAILED yielded null pointer mappings explicitly"))?;
Ok(Self {
ptr: non_null_ptr,
capacity: aligned_capacity,
})
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.capacity) }
}
}
impl Drop for HugePageBuffer {
fn drop(&mut self) {
unsafe {
munmap(self.ptr.as_ptr() as *mut libc::c_void, self.capacity);
}
}
}