buddy_slab_allocator/slab/
mod.rs1pub mod cache;
10pub mod page;
11pub mod size_class;
12
13pub use page::SlabPageHeader;
14pub use size_class::SizeClass;
15
16use cache::{CacheDeallocResult, SlabCache};
17use core::alloc::Layout;
18use core::ptr::NonNull;
19
20use crate::error::{AllocError, AllocResult};
21
22pub enum SlabAllocResult {
24 Allocated(NonNull<u8>),
26 NeedsSlab { size_class: SizeClass, pages: usize },
30}
31
32pub enum SlabDeallocResult {
34 Done,
36 FreeSlab { base: usize, pages: usize },
38}
39
40pub struct SlabAllocator<const PAGE_SIZE: usize = 0x1000> {
42 caches: [SlabCache; SizeClass::COUNT],
43}
44
45impl<const PAGE_SIZE: usize> SlabAllocator<PAGE_SIZE> {
46 pub const fn new() -> Self {
48 Self {
49 caches: [
50 SlabCache::new(SizeClass::Bytes8),
51 SlabCache::new(SizeClass::Bytes16),
52 SlabCache::new(SizeClass::Bytes32),
53 SlabCache::new(SizeClass::Bytes64),
54 SlabCache::new(SizeClass::Bytes128),
55 SlabCache::new(SizeClass::Bytes256),
56 SlabCache::new(SizeClass::Bytes512),
57 SlabCache::new(SizeClass::Bytes1024),
58 SlabCache::new(SizeClass::Bytes2048),
59 ],
60 }
61 }
62}
63
64impl<const PAGE_SIZE: usize> Default for SlabAllocator<PAGE_SIZE> {
65 fn default() -> Self {
66 Self::new()
67 }
68}
69
70impl<const PAGE_SIZE: usize> SlabAllocator<PAGE_SIZE> {
71 pub fn alloc(&mut self, layout: Layout) -> AllocResult<SlabAllocResult> {
76 let sc = SizeClass::from_layout(layout).ok_or(AllocError::InvalidParam)?;
77 let cache = &mut self.caches[sc.index()];
78
79 match cache.alloc_object::<PAGE_SIZE>() {
80 Some(addr) => {
81 let ptr = unsafe { NonNull::new_unchecked(addr as *mut u8) };
83 Ok(SlabAllocResult::Allocated(ptr))
84 }
85 None => Ok(SlabAllocResult::NeedsSlab {
86 size_class: sc,
87 pages: sc.slab_pages(PAGE_SIZE),
88 }),
89 }
90 }
91
92 pub fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) -> SlabDeallocResult {
97 let sc = SizeClass::from_layout(layout).expect("layout exceeds slab size");
98 let cache = &mut self.caches[sc.index()];
99
100 match cache.dealloc_object::<PAGE_SIZE>(ptr.as_ptr() as usize) {
101 CacheDeallocResult::Done => SlabDeallocResult::Done,
102 CacheDeallocResult::FreeSlab { base, pages } => {
103 SlabDeallocResult::FreeSlab { base, pages }
104 }
105 }
106 }
107
108 pub fn add_slab(&mut self, size_class: SizeClass, base: usize, bytes: usize, owner_cpu: u16) {
112 self.caches[size_class.index()].add_slab(base, bytes, owner_cpu);
113 }
114}