use crate::lock::SpinLock;
use crate::os;
use crate::stats;
use core::marker::PhantomData;
use core::ptr::null_mut;
const BLOCK: usize = 1 << 21;
static BASE: SpinLock<(*mut u8, usize)> = SpinLock::new((null_mut(), 0));
pub unsafe fn alloc(size: usize, align: usize) -> *mut u8 {
let mut base = BASE.lock();
let (cur, end) = *base;
let mut p = cur.map_addr(|a| os::round_up(a, align));
if cur.is_null() || p.addr() + size > end {
let len = BLOCK.max(os::round_up(size + align, os::page_size()));
let m = os::map(len);
if m.is_null() {
return null_mut();
}
stats::METADATA_BYTES.add(len);
p = m.map_addr(|a| os::round_up(a, align));
*base = (p, m.addr() + len);
}
base.0 = p.add(size);
p
}
#[cfg(all(unix, not(miri)))]
pub(crate) fn fork_lock() {
BASE.acquire();
}
#[cfg(all(unix, not(miri)))]
pub(crate) unsafe fn fork_unlock() {
BASE.release();
}
pub struct Pool<T> {
free: SpinLock<*mut u8>,
_t: PhantomData<*mut T>,
}
unsafe impl<T> Sync for Pool<T> {}
impl<T> Pool<T> {
pub const fn new() -> Self {
Pool {
free: SpinLock::new(null_mut()),
_t: PhantomData,
}
}
pub unsafe fn alloc(&self) -> *mut T {
{
let mut head = self.free.lock();
let p = *head;
if !p.is_null() {
*head = *p.cast::<*mut u8>();
return p.cast();
}
}
alloc(size_of::<T>().max(8), align_of::<T>().max(8)).cast()
}
#[cfg(all(unix, not(miri)))]
pub fn fork_lock(&self) {
self.free.acquire();
}
#[cfg(all(unix, not(miri)))]
pub unsafe fn fork_unlock(&self) {
self.free.release();
}
pub unsafe fn free(&self, p: *mut T) {
let mut head = self.free.lock();
*p.cast::<*mut u8>() = *head;
*head = p.cast();
}
}