mirror of
https://github.com/italicsjenga/agb.git
synced 2025-01-23 07:36:33 +11:00
A nice allocator!! Merges blocks together
This commit is contained in:
parent
03e9517215
commit
49c8720c8c
3 changed files with 116 additions and 41 deletions
|
@ -1,6 +1,7 @@
|
||||||
use core::alloc::{GlobalAlloc, Layout};
|
use core::alloc::{GlobalAlloc, Layout};
|
||||||
|
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
|
use core::convert::TryInto;
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
|
|
||||||
use crate::interrupt::free;
|
use crate::interrupt::free;
|
||||||
|
@ -25,6 +26,8 @@ impl Block {
|
||||||
aligned_to.align(),
|
aligned_to.align(),
|
||||||
)
|
)
|
||||||
.expect("too large allocation")
|
.expect("too large allocation")
|
||||||
|
.align_to(8)
|
||||||
|
.expect("too large allocation")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,10 +50,55 @@ impl BlockAllocator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn number_of_blocks(&self) -> u32 {
|
||||||
|
free(|key| {
|
||||||
|
let mut state = self.state.borrow(*key).borrow_mut();
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
|
||||||
|
let mut list_ptr = &mut state.first_free_block;
|
||||||
|
while let Some(mut curr) = list_ptr {
|
||||||
|
count += 1;
|
||||||
|
list_ptr = &mut curr.as_mut().next;
|
||||||
|
}
|
||||||
|
|
||||||
|
count
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn new_block(&self, layout: Layout, cs: &CriticalSection) -> *mut u8 {
|
fn new_block(&self, layout: Layout, cs: &CriticalSection) -> *mut u8 {
|
||||||
let overall_layout = Block::either_layout(layout);
|
let overall_layout = Block::either_layout(layout);
|
||||||
self.inner_allocator.alloc_critical(overall_layout, cs)
|
self.inner_allocator.alloc_critical(overall_layout, cs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn normalise(&self) {
|
||||||
|
free(|key| {
|
||||||
|
let mut state = self.state.borrow(*key).borrow_mut();
|
||||||
|
|
||||||
|
let mut list_ptr = &mut state.first_free_block;
|
||||||
|
|
||||||
|
while let Some(mut curr) = list_ptr {
|
||||||
|
if let Some(next_elem) = curr.as_mut().next {
|
||||||
|
let difference = next_elem
|
||||||
|
.as_ptr()
|
||||||
|
.cast::<u8>()
|
||||||
|
.offset_from(curr.as_ptr().cast::<u8>());
|
||||||
|
let usize_difference: usize = difference
|
||||||
|
.try_into()
|
||||||
|
.expect("distances in alloc'd blocks must be positive");
|
||||||
|
|
||||||
|
if usize_difference == curr.as_mut().size {
|
||||||
|
let current = curr.as_mut();
|
||||||
|
let next = next_elem.as_ref();
|
||||||
|
|
||||||
|
current.size += next.size;
|
||||||
|
current.next = next.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list_ptr = &mut curr.as_mut().next;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl GlobalAlloc for BlockAllocator {
|
unsafe impl GlobalAlloc for BlockAllocator {
|
||||||
|
@ -58,10 +106,10 @@ unsafe impl GlobalAlloc for BlockAllocator {
|
||||||
// find a block that this current request fits in
|
// find a block that this current request fits in
|
||||||
let full_layout = Block::either_layout(layout);
|
let full_layout = Block::either_layout(layout);
|
||||||
|
|
||||||
let (block_after_layout, block_after_layout_offset) =
|
let (block_after_layout, block_after_layout_offset) = full_layout
|
||||||
full_layout.extend(Layout::new::<Block>()).unwrap();
|
.extend(Layout::new::<Block>().align_to(8).unwrap().pad_to_align())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
{
|
|
||||||
free(|key| {
|
free(|key| {
|
||||||
let mut state = self.state.borrow(*key).borrow_mut();
|
let mut state = self.state.borrow(*key).borrow_mut();
|
||||||
let mut current_block = state.first_free_block;
|
let mut current_block = state.first_free_block;
|
||||||
|
@ -94,18 +142,41 @@ unsafe impl GlobalAlloc for BlockAllocator {
|
||||||
self.new_block(layout, key)
|
self.new_block(layout, key)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||||
let new_layout = Block::either_layout(layout);
|
let new_layout = Block::either_layout(layout).pad_to_align();
|
||||||
free(|key| {
|
free(|key| {
|
||||||
let mut state = self.state.borrow(*key).borrow_mut();
|
let mut state = self.state.borrow(*key).borrow_mut();
|
||||||
|
|
||||||
|
let mut list_ptr = &mut state.first_free_block;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match list_ptr {
|
||||||
|
Some(mut current_block) => {
|
||||||
|
if current_block.as_ptr().cast() > ptr {
|
||||||
let new_block_content = Block {
|
let new_block_content = Block {
|
||||||
size: new_layout.size(),
|
size: new_layout.size(),
|
||||||
next: state.first_free_block,
|
next: Some(current_block),
|
||||||
};
|
};
|
||||||
*ptr.cast() = new_block_content;
|
*ptr.cast() = new_block_content;
|
||||||
state.first_free_block = NonNull::new(ptr.cast()).map(SendNonNull);
|
*list_ptr = NonNull::new(ptr.cast()).map(SendNonNull);
|
||||||
})
|
break;
|
||||||
|
}
|
||||||
|
list_ptr = &mut current_block.as_mut().next;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// reached the end of the list without finding a place to insert the value
|
||||||
|
let new_block_content = Block {
|
||||||
|
size: new_layout.size(),
|
||||||
|
next: None,
|
||||||
|
};
|
||||||
|
*ptr.cast() = new_block_content;
|
||||||
|
*list_ptr = NonNull::new(ptr.cast()).map(SendNonNull);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.normalise();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl BumpAllocator {
|
||||||
let alignment_bitmask = layout.align() - 1;
|
let alignment_bitmask = layout.align() - 1;
|
||||||
let fixup = ptr & alignment_bitmask;
|
let fixup = ptr & alignment_bitmask;
|
||||||
|
|
||||||
let amount_to_add = layout.align() - fixup;
|
let amount_to_add = (layout.align() - fixup) & alignment_bitmask;
|
||||||
|
|
||||||
let resulting_ptr = ptr + amount_to_add;
|
let resulting_ptr = ptr + amount_to_add;
|
||||||
let new_current_ptr = resulting_ptr + layout.size();
|
let new_current_ptr = resulting_ptr + layout.size();
|
||||||
|
|
|
@ -35,6 +35,10 @@ const EWRAM_END: usize = 0x0204_0000;
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static GLOBAL_ALLOC: BlockAllocator = unsafe { BlockAllocator::new() };
|
static GLOBAL_ALLOC: BlockAllocator = unsafe { BlockAllocator::new() };
|
||||||
|
|
||||||
|
pub unsafe fn number_of_blocks() -> u32 {
|
||||||
|
GLOBAL_ALLOC.number_of_blocks()
|
||||||
|
}
|
||||||
|
|
||||||
#[alloc_error_handler]
|
#[alloc_error_handler]
|
||||||
fn alloc_error(layout: Layout) -> ! {
|
fn alloc_error(layout: Layout) -> ! {
|
||||||
panic!(
|
panic!(
|
||||||
|
|
Loading…
Add table
Reference in a new issue