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分配器
new() -> SlabAllocator25 pub fn new() -> SlabAllocator {
26 debug!("trying to new a slab_allocator");
27 SlabAllocator {
28 zone: ZoneAllocator::new(),
29 }
30 }
31
32 /// 为对象(2K以内)分配内存空间
allocate(&mut self, layout: Layout) -> *mut u833 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 /// 释放内存空间
deallocate( &mut self, ptr: *mut u8, layout: Layout, ) -> Result<(), AllocationError>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分配器
slab_init()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初始化状态
slab_init_state() -> bool76 pub fn slab_init_state() -> bool {
77 unsafe { *SLABINITSTATE.get_mut() }
78 }
79
slab_usage() -> SlabUsage80 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 {
free_slab_page(&self, base_addr: *mut u8, size: usize)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