1 use core::{alloc::Layout, ptr::NonNull, sync::atomic::AtomicBool};
2
3 use alloc::boxed::Box;
4 use log::debug;
5 use slabmalloc::*;
6
7 // 全局slab分配器
8 pub(crate) static mut SLABALLOCATOR: Option<SlabAllocator> = None;
9
10 // slab初始化状态
11 pub(crate) static mut SLABINITSTATE: AtomicBool = AtomicBool::new(false);
12
13 /// slab分配器,实际为一堆小的allocator,可以在里面装4K的page
14 /// 利用这些allocator可以为对象分配不同大小的空间
15 pub(crate) struct SlabAllocator {
16 zone: ZoneAllocator<'static>,
17 }
18
19 impl SlabAllocator {
20 /// 创建slab分配器
new() -> SlabAllocator21 pub fn new() -> SlabAllocator {
22 debug!("trying to new a slab_allocator");
23 SlabAllocator {
24 zone: ZoneAllocator::new(),
25 }
26 }
27
28 /// 为对象(2K以内)分配内存空间
allocate(&mut self, layout: Layout) -> *mut u829 pub(crate) unsafe fn allocate(&mut self, layout: Layout) -> *mut u8 {
30 match self.zone.allocate(layout) {
31 Ok(nptr) => nptr.as_ptr(),
32 Err(AllocationError::OutOfMemory) => {
33 let boxed_page = ObjectPage::new();
34 let leaked_page = Box::leak(boxed_page);
35 self.zone
36 .refill(layout, leaked_page)
37 .expect("Could not refill?");
38 self.zone
39 .allocate(layout)
40 .expect("Should succeed after refill")
41 .as_ptr()
42 }
43 Err(AllocationError::InvalidLayout) => panic!("Can't allocate this size"),
44 }
45 }
46
47 /// 释放内存空间
deallocate( &mut self, ptr: *mut u8, layout: Layout, ) -> Result<(), AllocationError>48 pub(crate) unsafe fn deallocate(
49 &mut self,
50 ptr: *mut u8,
51 layout: Layout,
52 ) -> Result<(), AllocationError> {
53 if let Some(nptr) = NonNull::new(ptr) {
54 self.zone
55 .deallocate(nptr, layout)
56 .expect("Couldn't deallocate");
57 return Ok(());
58 } else {
59 return Ok(());
60 }
61 }
62 }
63
64 /// 初始化slab分配器
slab_init()65 pub unsafe fn slab_init() {
66 debug!("trying to init a slab_allocator");
67 SLABALLOCATOR = Some(SlabAllocator::new());
68 SLABINITSTATE = true.into();
69 }
70
71 // 查看slab初始化状态
slab_init_state() -> bool72 pub fn slab_init_state() -> bool {
73 unsafe { *SLABINITSTATE.get_mut() }
74 }
75
slab_usage() -> SlabUsage76 pub unsafe fn slab_usage() -> SlabUsage {
77 if let Some(ref mut slab) = SLABALLOCATOR {
78 slab.zone.usage()
79 } else {
80 SlabUsage::new(0, 0)
81 }
82 }
83