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