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