pub mod cache;
pub mod page;
pub mod size_class;
pub use page::SlabPageHeader;
pub use size_class::SizeClass;
use cache::{CacheDeallocResult, SlabCache};
use core::alloc::Layout;
use core::ptr::NonNull;
use crate::error::{AllocError, AllocResult};
pub enum SlabAllocResult {
Allocated(NonNull<u8>),
NeedsSlab { size_class: SizeClass, pages: usize },
}
pub enum SlabDeallocResult {
Done,
FreeSlab { base: usize, pages: usize },
}
pub struct SlabAllocator<const PAGE_SIZE: usize = 0x1000> {
caches: [SlabCache; SizeClass::COUNT],
}
impl<const PAGE_SIZE: usize> SlabAllocator<PAGE_SIZE> {
pub const fn new() -> Self {
Self {
caches: [
SlabCache::new(SizeClass::Bytes8),
SlabCache::new(SizeClass::Bytes16),
SlabCache::new(SizeClass::Bytes32),
SlabCache::new(SizeClass::Bytes64),
SlabCache::new(SizeClass::Bytes128),
SlabCache::new(SizeClass::Bytes256),
SlabCache::new(SizeClass::Bytes512),
SlabCache::new(SizeClass::Bytes1024),
SlabCache::new(SizeClass::Bytes2048),
],
}
}
}
impl<const PAGE_SIZE: usize> Default for SlabAllocator<PAGE_SIZE> {
fn default() -> Self {
Self::new()
}
}
impl<const PAGE_SIZE: usize> SlabAllocator<PAGE_SIZE> {
pub fn alloc(&mut self, layout: Layout) -> AllocResult<SlabAllocResult> {
let sc = SizeClass::from_layout(layout).ok_or(AllocError::InvalidParam)?;
let cache = &mut self.caches[sc.index()];
match cache.alloc_object::<PAGE_SIZE>() {
Some(addr) => {
let ptr = unsafe { NonNull::new_unchecked(addr as *mut u8) };
Ok(SlabAllocResult::Allocated(ptr))
}
None => Ok(SlabAllocResult::NeedsSlab {
size_class: sc,
pages: sc.slab_pages(PAGE_SIZE),
}),
}
}
pub fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) -> SlabDeallocResult {
let sc = SizeClass::from_layout(layout).expect("layout exceeds slab size");
let cache = &mut self.caches[sc.index()];
match cache.dealloc_object::<PAGE_SIZE>(ptr.as_ptr() as usize) {
CacheDeallocResult::Done => SlabDeallocResult::Done,
CacheDeallocResult::FreeSlab { base, pages } => {
SlabDeallocResult::FreeSlab { base, pages }
}
}
}
pub fn add_slab(&mut self, size_class: SizeClass, base: usize, bytes: usize, owner_cpu: u16) {
self.caches[size_class.index()].add_slab(base, bytes, owner_cpu);
}
}