xref: /DragonOS/kernel/src/mm/allocator/slab.rs (revision fae6e9ade46a52976ad5d099643d51cc20876448)
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 use crate::{arch::MMArch, mm::MemoryManagementArch, KERNEL_ALLOCATOR};
8 
9 // 全局slab分配器
10 pub(crate) static mut SLABALLOCATOR: Option<SlabAllocator> = None;
11 
12 // slab初始化状态
13 pub(crate) static mut SLABINITSTATE: AtomicBool = AtomicBool::new(false);
14 
15 static SLAB_CALLBACK: SlabCallback = SlabCallback;
16 
17 /// slab分配器,实际为一堆小的allocator,可以在里面装4K的page
18 /// 利用这些allocator可以为对象分配不同大小的空间
19 pub(crate) struct SlabAllocator {
20     zone: ZoneAllocator<'static>,
21 }
22 
23 impl SlabAllocator {
24     /// 创建slab分配器
25     pub fn new() -> SlabAllocator {
26         debug!("trying to new a slab_allocator");
27         SlabAllocator {
28             zone: ZoneAllocator::new(),
29         }
30     }
31 
32     /// 为对象(2K以内)分配内存空间
33     pub(crate) unsafe fn allocate(&mut self, layout: Layout) -> *mut u8 {
34         match self.zone.allocate(layout) {
35             Ok(nptr) => nptr.as_ptr(),
36             Err(AllocationError::OutOfMemory) => {
37                 let boxed_page = ObjectPage::new();
38                 let leaked_page = Box::leak(boxed_page);
39                 self.zone
40                     .refill(layout, leaked_page)
41                     .expect("Could not refill?");
42                 self.zone
43                     .allocate(layout)
44                     .expect("Should succeed after refill")
45                     .as_ptr()
46             }
47             Err(AllocationError::InvalidLayout) => panic!("Can't allocate this size"),
48         }
49     }
50 
51     /// 释放内存空间
52     pub(crate) unsafe fn deallocate(
53         &mut self,
54         ptr: *mut u8,
55         layout: Layout,
56     ) -> Result<(), AllocationError> {
57         if let Some(nptr) = NonNull::new(ptr) {
58             self.zone
59                 .deallocate(nptr, layout, &SLAB_CALLBACK)
60                 .expect("Couldn't deallocate");
61             return Ok(());
62         } else {
63             return Ok(());
64         }
65     }
66 }
67 
68 /// 初始化slab分配器
69 pub unsafe fn slab_init() {
70     debug!("trying to init a slab_allocator");
71     SLABALLOCATOR = Some(SlabAllocator::new());
72     SLABINITSTATE = true.into();
73 }
74 
75 // 查看slab初始化状态
76 pub fn slab_init_state() -> bool {
77     unsafe { *SLABINITSTATE.get_mut() }
78 }
79 
80 pub unsafe fn slab_usage() -> SlabUsage {
81     if let Some(ref mut slab) = SLABALLOCATOR {
82         slab.zone.usage()
83     } else {
84         SlabUsage::new(0, 0)
85     }
86 }
87 
88 /// 归还slab_page给buddy的回调
89 pub struct SlabCallback;
90 impl CallBack for SlabCallback {
91     unsafe fn free_slab_page(&self, base_addr: *mut u8, size: usize) {
92         assert_eq!(base_addr as usize & (MMArch::PAGE_SIZE - 1), 0); // 确认地址4k对齐
93         assert_eq!(size, MMArch::PAGE_SIZE); // 确认释放的slab_page大小
94         KERNEL_ALLOCATOR.free_in_buddy(base_addr, Layout::from_size_align_unchecked(size, 1));
95     }
96 }
97