use const_default1::ConstDefault;
use core::{
marker::PhantomData,
ptr::{addr_of_mut, null_mut, NonNull},
};
use super::GlobalTlsfOptions;
const MIN_ALIGN: usize = crate::GRANULARITY;
const ALLOC_UNIT: usize = if cfg!(miri) { 1 << 14 } else { 1 << 16 };
pub struct Mutex(());
impl ConstDefault for Mutex {
const DEFAULT: Self = Self(());
}
static mut MUTEX: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER;
impl Mutex {
#[inline]
pub fn lock(&self) {
unsafe { libc::pthread_mutex_lock(addr_of_mut!(MUTEX)) };
}
#[inline]
pub fn unlock(&self) {
unsafe { libc::pthread_mutex_unlock(addr_of_mut!(MUTEX)) };
}
}
pub struct Source<Options>(PhantomData<fn() -> Options>);
impl<Options> ConstDefault for Source<Options> {
const DEFAULT: Self = Self(PhantomData);
}
static mut PAGE_SIZE_M1: usize = 0;
#[cold]
fn init_page_size() -> usize {
unsafe {
let page_size = (libc::sysconf(libc::_SC_PAGESIZE) as usize).max(ALLOC_UNIT);
if !page_size.is_power_of_two() {
libc::abort();
}
PAGE_SIZE_M1 = page_size - 1;
if page_size < MIN_ALIGN {
libc::abort();
}
PAGE_SIZE_M1
}
}
#[inline]
fn ensure_page_size_m1() -> usize {
let page_size_m1 = unsafe { PAGE_SIZE_M1 };
if page_size_m1 == 0 {
init_page_size()
} else {
page_size_m1
}
}
unsafe impl<Options: GlobalTlsfOptions> crate::flex::FlexSource for Source<Options> {
#[inline]
unsafe fn alloc(&mut self, min_size: usize) -> Option<NonNull<[u8]>> {
let page_size_m1 = ensure_page_size_m1();
let num_bytes = min_size.checked_add(page_size_m1)? & !page_size_m1;
let ptr = libc::mmap(
null_mut(),
num_bytes,
libc::PROT_WRITE | libc::PROT_READ,
libc::MAP_ANONYMOUS | libc::MAP_PRIVATE,
-1,
0,
);
if ptr == libc::MAP_FAILED {
return None;
}
NonNull::new(core::ptr::slice_from_raw_parts_mut(
ptr as *mut u8,
num_bytes,
))
}
#[inline]
#[cfg(target_os = "linux")]
unsafe fn realloc_inplace_grow(
&mut self,
ptr: NonNull<[u8]>,
min_new_len: usize,
) -> Option<usize> {
use crate::utils::nonnull_slice_len;
if !Options::COALESCE_POOLS {
return None;
}
let page_size_m1 = ensure_page_size_m1();
let num_bytes = min_new_len.checked_add(page_size_m1)? & !page_size_m1;
let num_growth_bytes = num_bytes - nonnull_slice_len(ptr);
let ptr_end = (ptr.as_ptr() as *mut u8).wrapping_add(nonnull_slice_len(ptr));
let ptr_growth_start = libc::mmap(
ptr_end as _,
num_growth_bytes,
libc::PROT_WRITE | libc::PROT_READ,
libc::MAP_ANONYMOUS | libc::MAP_PRIVATE | libc::MAP_FIXED_NOREPLACE,
-1,
0,
);
if ptr_growth_start != ptr_end as _ {
libc::munmap(ptr_growth_start, num_growth_bytes);
None
} else if ptr_growth_start == libc::MAP_FAILED {
None
} else {
Some(num_bytes)
}
}
#[inline]
#[cfg(target_os = "linux")]
fn supports_realloc_inplace_grow(&self) -> bool {
Options::COALESCE_POOLS
}
#[inline]
fn min_align(&self) -> usize {
MIN_ALIGN
}
}