use std::ptr::NonNull;
use crate::Pointer;
trait PlatformSpecificMemory {
unsafe fn request_memory(length: usize) -> Pointer<u8>;
unsafe fn return_memory(address: NonNull<u8>, length: usize);
unsafe fn page_size() -> usize;
}
pub(crate) struct Platform;
pub(crate) static mut PAGE_SIZE: usize = 0;
#[inline]
pub(crate) fn page_size() -> usize {
unsafe {
if PAGE_SIZE == 0 {
PAGE_SIZE = Platform::page_size();
}
PAGE_SIZE
}
}
pub unsafe fn request_memory(length: usize) -> Pointer<u8> {
Platform::request_memory(length)
}
pub unsafe fn return_memory(address: NonNull<u8>, length: usize) {
Platform::return_memory(address, length)
}
#[cfg(unix)]
#[cfg(not(miri))]
mod unix {
use std::ptr::{self, NonNull};
use libc;
use super::{Platform, PlatformSpecificMemory};
use crate::Pointer;
impl PlatformSpecificMemory for Platform {
unsafe fn request_memory(length: usize) -> Pointer<u8> {
let null = ptr::null_mut::<libc::c_void>();
let protection = libc::PROT_READ | libc::PROT_WRITE;
let flags = libc::MAP_PRIVATE | libc::MAP_ANONYMOUS;
match libc::mmap(null, length, protection, flags, -1, 0) {
libc::MAP_FAILED => None,
address => Some(NonNull::new_unchecked(address as *mut u8)),
}
}
unsafe fn return_memory(address: NonNull<u8>, length: usize) {
if libc::munmap(address.cast::<libc::c_void>().as_ptr(), length) != 0 {
}
}
unsafe fn page_size() -> usize {
libc::sysconf(libc::_SC_PAGE_SIZE) as usize
}
}
}
#[cfg(windows)]
#[cfg(not(miri))]
mod windows {
use std::{mem::MaybeUninit, ptr::NonNull};
use windows::Win32::System::{Memory, SystemInformation};
use super::{Platform, PlatformSpecificMemory};
use crate::Pointer;
impl PlatformSpecificMemory for Platform {
unsafe fn request_memory(length: usize) -> Pointer<u8> {
let protection = Memory::PAGE_READWRITE;
let flags = Memory::MEM_RESERVE | Memory::MEM_COMMIT;
let address = Memory::VirtualAlloc(None, length, flags, protection);
if address.is_null() {
None
} else {
Some(NonNull::new_unchecked(address as *mut u8))
}
}
unsafe fn return_memory(address: NonNull<u8>, _length: usize) {
let address = address.cast::<std::ffi::c_void>().as_ptr();
let length = 0;
let flags = Memory::MEM_RELEASE;
if !Memory::VirtualFree(address, length, flags).as_bool() {
}
}
unsafe fn page_size() -> usize {
let mut system_info = MaybeUninit::uninit();
SystemInformation::GetSystemInfo(system_info.as_mut_ptr());
system_info.assume_init().dwPageSize as usize
}
}
}
#[cfg(miri)]
mod miri {
use std::{alloc, ptr::NonNull};
use super::{page_size, Platform, PlatformSpecificMemory};
use crate::Pointer;
fn to_layout(length: usize) -> std::alloc::Layout {
alloc::Layout::from_size_align(length, page_size()).unwrap()
}
impl PlatformSpecificMemory for Platform {
unsafe fn request_memory(length: usize) -> Pointer<u8> {
let address = alloc::alloc(to_layout(length));
Some(NonNull::new_unchecked(address))
}
unsafe fn return_memory(address: NonNull<u8>, length: usize) {
alloc::dealloc(address.as_ptr(), to_layout(length));
}
unsafe fn page_size() -> usize {
4096
}
}
}