-
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.
Merge pull request #35 from orust-org/main
Merginng page branch with main
- Loading branch information
Showing
6 changed files
with
318 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,56 @@ | ||
use super::{align_up,Locked}; | ||
use alloc::alloc::{GlobalAlloc, Layout}; | ||
use core::ptr; | ||
|
||
pub struct BumpAllocator { | ||
heap_start: usize, | ||
heap_end: usize, | ||
next: usize, | ||
allocations: usize, | ||
} | ||
|
||
impl BumpAllocator { | ||
/// Creates a new empty bump allocator. | ||
pub const fn new() -> Self { | ||
BumpAllocator { | ||
heap_start: 0, | ||
heap_end: 0, | ||
next: 0, | ||
allocations: 0, | ||
} | ||
} | ||
pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) { | ||
self.heap_start = heap_start; | ||
self.heap_end = heap_start + heap_size; | ||
self.next = heap_start; | ||
} | ||
} | ||
|
||
unsafe impl GlobalAlloc for Locked<BumpAllocator> { | ||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { | ||
let mut bump = self.lock(); // get a mutable reference | ||
|
||
let alloc_start = align_up(bump.next, layout.align()); | ||
let alloc_end = match alloc_start.checked_add(layout.size()) { | ||
Some(end) => end, | ||
None => return ptr::null_mut(), | ||
}; | ||
|
||
if alloc_end > bump.heap_end { | ||
ptr::null_mut() // out of memory | ||
} else { | ||
bump.next = alloc_end; | ||
bump.allocations += 1; | ||
alloc_start as *mut u8 | ||
} | ||
} | ||
|
||
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) { | ||
let mut bump = self.lock(); // get a mutable reference | ||
|
||
bump.allocations -= 1; | ||
if bump.allocations == 0 { | ||
bump.next = bump.heap_start; | ||
} | ||
} | ||
} |
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) | ||
} | ||
} |
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,132 @@ | ||
use super::align_up; | ||
use core::mem; | ||
use super::Locked; | ||
use alloc::alloc::{GlobalAlloc, Layout}; | ||
use core::ptr; | ||
|
||
pub struct LinkedListAllocator { | ||
head: ListNode, | ||
} | ||
|
||
unsafe impl GlobalAlloc for Locked<LinkedListAllocator> { | ||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { | ||
// perform layout adjustments | ||
let (size, align) = LinkedListAllocator::size_align(layout); | ||
let mut allocator = self.lock(); | ||
|
||
if let Some((region, alloc_start)) = allocator.find_region(size, align) { | ||
let alloc_end = alloc_start.checked_add(size).expect("overflow"); | ||
let excess_size = region.end_addr() - alloc_end; | ||
if excess_size > 0 { | ||
allocator.add_free_region(alloc_end, excess_size); | ||
} | ||
alloc_start as *mut u8 | ||
} else { | ||
ptr::null_mut() | ||
} | ||
} | ||
|
||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { | ||
// perform layout adjustments | ||
let (size, _) = LinkedListAllocator::size_align(layout); | ||
|
||
self.lock().add_free_region(ptr as usize, size) | ||
} | ||
} | ||
|
||
|
||
impl LinkedListAllocator { | ||
/// Creates an empty LinkedListAllocator. | ||
pub const fn new() -> Self { | ||
Self { | ||
head: ListNode::new(0), | ||
} | ||
} | ||
pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) { | ||
self.add_free_region(heap_start, heap_size); | ||
} | ||
unsafe fn add_free_region(&mut self, addr: usize, size: usize) { | ||
assert_eq!(align_up(addr, mem::align_of::<ListNode>()), addr); | ||
assert!(size >= mem::size_of::<ListNode>()); | ||
|
||
// create a new list node and append it at the start of the list | ||
let mut node = ListNode::new(size); | ||
node.next = self.head.next.take(); | ||
let node_ptr = addr as *mut ListNode; | ||
node_ptr.write(node); | ||
self.head.next = Some(&mut *node_ptr) | ||
} | ||
|
||
fn find_region(&mut self, size: usize, align: usize) | ||
-> Option<(&'static mut ListNode, usize)> | ||
{ | ||
// reference to current list node, updated for each iteration | ||
let mut current = &mut self.head; | ||
// look for a large enough memory region in linked list | ||
while let Some(ref mut region) = current.next { | ||
if let Ok(alloc_start) = Self::alloc_from_region(®ion, size, align) { | ||
// region suitable for allocation -> remove node from list | ||
let next = region.next.take(); | ||
let ret = Some((current.next.take().unwrap(), alloc_start)); | ||
current.next = next; | ||
return ret; | ||
} else { | ||
// region not suitable -> continue with next region | ||
current = current.next.as_mut().unwrap(); | ||
} | ||
} | ||
|
||
// no suitable region found | ||
None | ||
} | ||
|
||
fn alloc_from_region(region: &ListNode, size: usize, align: usize) | ||
-> Result<usize, ()> | ||
{ | ||
let alloc_start = align_up(region.start_addr(), align); | ||
let alloc_end = alloc_start.checked_add(size).ok_or(())?; | ||
|
||
if alloc_end > region.end_addr() { | ||
// region too small | ||
return Err(()); | ||
} | ||
|
||
let excess_size = region.end_addr() - alloc_end; | ||
if excess_size > 0 && excess_size < mem::size_of::<ListNode>() { | ||
// rest of region too small to hold a ListNode (required because the | ||
// allocation splits the region in a used and a free part) | ||
return Err(()); | ||
} | ||
|
||
// region suitable for allocation | ||
Ok(alloc_start) | ||
} | ||
|
||
fn size_align(layout: Layout) -> (usize, usize) { | ||
let layout = layout | ||
.align_to(mem::align_of::<ListNode>()) | ||
.expect("adjusting alignment failed") | ||
.pad_to_align(); | ||
let size = layout.size().max(mem::size_of::<ListNode>()); | ||
(size, layout.align()) | ||
} | ||
} | ||
struct ListNode { | ||
size: usize, | ||
next: Option<&'static mut ListNode>, | ||
} | ||
|
||
impl ListNode { | ||
const fn new(size: usize) -> Self { | ||
ListNode { size, next: None } | ||
} | ||
|
||
fn start_addr(&self) -> usize { | ||
self as *const Self as usize | ||
} | ||
|
||
fn end_addr(&self) -> usize { | ||
self.start_addr() + self.size | ||
} | ||
} | ||
|
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