use super::Page;
use core::ffi::c_void;
use core::ptr::NonNull;
pub fn page_size() -> usize {
use windows::Win32::System::SystemInformation::{GetSystemInfo, SYSTEM_INFO};
let mut sysinfo = SYSTEM_INFO::default();
let sysinfo_ptr = &mut sysinfo as *mut SYSTEM_INFO;
unsafe { GetSystemInfo(sysinfo_ptr) };
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
{
sysinfo.dwPageSize as usize
}
}
#[derive(Debug, Clone, thiserror::Error)]
pub enum PageAllocError {
#[error("could not map a memory page")]
VirtualAlloc,
#[error("could not lock memory page: {0}")]
VirtualLock(windows::core::Error),
}
impl Page {
fn as_c_ptr_mut(&self) -> *mut c_void {
self.as_ptr_mut() as *mut c_void
}
fn alloc_new() -> Result<Self, ()> {
use windows::Win32::System::Memory::{
MEM_COMMIT, MEM_RESERVE, PAGE_PROTECTION_FLAGS, PAGE_READWRITE,
VIRTUAL_ALLOCATION_TYPE, VirtualAlloc,
};
let page_size = page_size();
let alloc_type: VIRTUAL_ALLOCATION_TYPE = MEM_RESERVE | MEM_COMMIT;
let protect: PAGE_PROTECTION_FLAGS = PAGE_READWRITE;
let page_ptr: *mut c_void = unsafe { VirtualAlloc(None, page_size, alloc_type, protect) };
if page_ptr.is_null() {
Err(())
} else {
let page_ptr = unsafe {
NonNull::new_unchecked(page_ptr as *mut u8)
};
Ok(Self {
page_ptr,
page_size,
_phantom_pagemem: core::marker::PhantomData,
})
}
}
fn lock(&mut self) -> Result<(), windows::core::Error> {
use windows::Win32::System::Memory::VirtualLock;
unsafe { VirtualLock(self.as_c_ptr_mut(), self.page_size()) }
}
pub fn alloc_new_lock() -> Result<Self, PageAllocError> {
let mut page = Self::alloc_new().map_err(|_| PageAllocError::VirtualAlloc)?;
page.lock().map_err(|e| PageAllocError::VirtualLock(e))?;
Ok(page)
}
}
impl Drop for Page {
fn drop(&mut self) {
use windows::Win32::System::Memory::{MEM_RELEASE, VirtualFree};
unsafe { VirtualFree(self.as_c_ptr_mut(), 0, MEM_RELEASE) }.unwrap();
}
}