xref: /DragonOS/kernel/src/mm/allocator/slab.rs (revision 2eab6dd743e94a86a685f1f3c01e599adf86610a)
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分配器
21     pub fn new() -> SlabAllocator {
22         debug!("trying to new a slab_allocator");
23         SlabAllocator {
24             zone: ZoneAllocator::new(),
25         }
26     }
27 
28     /// 为对象(2K以内)分配内存空间
29     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     /// 释放内存空间
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分配器
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初始化状态
72 pub fn slab_init_state() -> bool {
73     unsafe { *SLABINITSTATE.get_mut() }
74 }
75 
76 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