use core::sync::atomic::{AtomicUsize, Ordering};
use crate::prim::{self, PrimError};
#[derive(Debug, Clone, Copy)]
pub struct OsBlock {
pub ptr: *mut u8,
pub size: usize,
pub is_large: bool,
pub is_zero: bool,
}
static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
static ALLOC_GRANULARITY: AtomicUsize = AtomicUsize::new(0);
static LARGE_PAGE_SIZE: AtomicUsize = AtomicUsize::new(usize::MAX);
fn config_init() {
let cfg = prim::mem_init();
PAGE_SIZE.store(cfg.page_size, Ordering::Relaxed);
ALLOC_GRANULARITY.store(cfg.alloc_granularity, Ordering::Relaxed);
LARGE_PAGE_SIZE.store(cfg.large_page_size, Ordering::Relaxed);
}
pub fn page_size() -> usize {
let v = PAGE_SIZE.load(Ordering::Relaxed);
if v != 0 {
return v;
}
config_init();
PAGE_SIZE.load(Ordering::Relaxed)
}
pub fn alloc_granularity() -> usize {
let v = ALLOC_GRANULARITY.load(Ordering::Relaxed);
if v != 0 {
return v;
}
config_init();
ALLOC_GRANULARITY.load(Ordering::Relaxed)
}
pub fn large_page_size() -> usize {
let v = LARGE_PAGE_SIZE.load(Ordering::Relaxed);
if v != usize::MAX {
return v;
}
config_init();
LARGE_PAGE_SIZE.load(Ordering::Relaxed)
}
pub fn page_align_up(size: usize) -> usize {
let ps = page_size();
size.max(1).div_ceil(ps) * ps
}
pub fn alloc_aligned(
size: usize,
alignment: usize,
commit: bool,
allow_large: bool,
) -> Result<OsBlock, PrimError> {
assert!(
alignment.is_power_of_two(),
"alignment must be a power of two"
);
let alignment = alignment.max(page_size());
let size = page_align_up(size);
let a = unsafe { prim::alloc(size, alignment, commit, allow_large)? };
debug_assert_eq!(
(a.ptr as usize) % alignment,
0,
"prim returned misaligned block"
);
Ok(OsBlock {
ptr: a.ptr,
size,
is_large: a.is_large,
is_zero: a.is_zero,
})
}
pub unsafe fn free(block: OsBlock) -> Result<(), PrimError> {
unsafe { prim::free(block.ptr, block.size) }
}
pub unsafe fn commit(ptr: *mut u8, size: usize) -> Result<bool, PrimError> {
unsafe { prim::commit(ptr, page_align_up(size)) }
}
pub unsafe fn decommit(ptr: *mut u8, size: usize) -> Result<bool, PrimError> {
unsafe { prim::decommit(ptr, page_align_up(size)) }
}
pub unsafe fn purge(ptr: *mut u8, size: usize, purge_decommits: bool) -> Result<bool, PrimError> {
if purge_decommits {
unsafe { decommit(ptr, size) }
} else {
unsafe { prim::reset(ptr, page_align_up(size))? };
Ok(false)
}
}
pub unsafe fn protect(ptr: *mut u8, size: usize, on: bool) -> Result<(), PrimError> {
unsafe { prim::protect(ptr, page_align_up(size), on) }
}