-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1c65628
commit a651087
Showing
2 changed files
with
95 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
use super::Locked; | ||
use alloc::alloc::GlobalAlloc; | ||
use alloc::alloc::Layout; | ||
use core::{mem, ptr, ptr::NonNull}; | ||
struct ListNode { | ||
next: Option<&'static mut ListNode>, | ||
} | ||
|
||
const BLOCK_SIZES: &[usize] = &[8, 16, 32, 64, 128, 256, 512, 1024, 2048]; | ||
|
||
pub struct FixedSizeBlockAllocator { | ||
list_heads: [Option<&'static mut ListNode>; BLOCK_SIZES.len()], | ||
fallback_allocator: linked_list_allocator::Heap, | ||
} | ||
|
||
unsafe impl GlobalAlloc for Locked<FixedSizeBlockAllocator> { | ||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { | ||
let mut allocator = self.lock(); | ||
match FixedSizeBlockAllocator::list_index(&layout) { | ||
Some(index) => { | ||
match allocator.list_heads[index].take() { | ||
Some(node) => { | ||
allocator.list_heads[index] = node.next.take(); | ||
node as *mut ListNode as *mut u8 | ||
} | ||
None => { | ||
// no block exists in list => allocate new block | ||
let block_size = BLOCK_SIZES[index]; | ||
// only works if all block sizes are a power of 2 | ||
let block_align = block_size; | ||
let layout = Layout::from_size_align(block_size, block_align) | ||
.unwrap(); | ||
allocator.fallback_alloc(layout) | ||
} | ||
} | ||
} | ||
None => allocator.fallback_alloc(layout), | ||
} | ||
} | ||
|
||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { | ||
let mut allocator = self.lock(); | ||
match FixedSizeBlockAllocator::list_index(&layout) { | ||
Some(index) => { | ||
let new_node = ListNode { | ||
next: allocator.list_heads[index].take(), | ||
}; | ||
// verify that block has size and alignment required for storing node | ||
assert!(mem::size_of::<ListNode>() <= BLOCK_SIZES[index]); | ||
assert!(mem::align_of::<ListNode>() <= BLOCK_SIZES[index]); | ||
let new_node_ptr = ptr as *mut ListNode; | ||
new_node_ptr.write(new_node); | ||
allocator.list_heads[index] = Some(&mut *new_node_ptr); | ||
} | ||
None => { | ||
let ptr = NonNull::new(ptr).unwrap(); | ||
allocator.fallback_allocator.deallocate(ptr, layout); | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl FixedSizeBlockAllocator { | ||
/// Creates an empty FixedSizeBlockAllocator. | ||
pub const fn new() -> Self { | ||
const EMPTY: Option<&'static mut ListNode> = None; | ||
FixedSizeBlockAllocator { | ||
list_heads: [EMPTY; BLOCK_SIZES.len()], | ||
fallback_allocator: linked_list_allocator::Heap::empty(), | ||
} | ||
} | ||
|
||
pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) { | ||
self.fallback_allocator.init(heap_start, heap_size); | ||
} | ||
|
||
/// Allocates using the fallback allocator. | ||
fn fallback_alloc(&mut self, layout: Layout) -> *mut u8 { | ||
match self.fallback_allocator.allocate_first_fit(layout) { | ||
Ok(ptr) => ptr.as_ptr(), | ||
Err(_) => ptr::null_mut(), | ||
} | ||
} | ||
|
||
/// Returns an index into the `BLOCK_SIZES` array. | ||
fn list_index(layout: &Layout) -> Option<usize> { | ||
let required_block_size = layout.size().max(layout.align()); | ||
BLOCK_SIZES.iter().position(|&s| s >= required_block_size) | ||
} | ||
} |