Fix first fit implementation of heap

This commit is contained in:
2025-12-20 16:51:18 +01:00
parent e22dc65588
commit b5d3417572
2 changed files with 77 additions and 35 deletions

View File

@@ -61,7 +61,7 @@ impl Heap {
unsafe fn find_first_fit(&self, size: usize) -> Result<*mut HeapHeader, NovaError> { unsafe fn find_first_fit(&self, size: usize) -> Result<*mut HeapHeader, NovaError> {
let mut current = self.start_address; let mut current = self.start_address;
while !fits(size, current) { while !fits(size, current) {
if let Some(next) = (*self.start_address).next { if let Some(next) = (*current).next {
current = next; current = next;
} else { } else {
return Err(NovaError::HeapFull); return Err(NovaError::HeapFull);
@@ -122,9 +122,11 @@ impl Heap {
}, },
) )
}; };
(*current).next = Some(new_address); unsafe {
(*current).free = false; (*current).next = Some(new_address);
(*current).size = size; (*current).free = false;
(*current).size = size;
}
} }
pub fn free(&self, pointer: *mut u8) -> Result<(), NovaError> { pub fn free(&self, pointer: *mut u8) -> Result<(), NovaError> {

View File

@@ -88,38 +88,78 @@ fn test_freeing_root() {
assert_eq!((*root_header).size, root_header_start_size); assert_eq!((*root_header).size, root_header_start_size);
assert!((*root_header).next.is_none()); assert!((*root_header).next.is_none());
} }
}
fn test_merging_free_sections() { #[test]
let heap_vector = Box::new([0u8; HEAP_SIZE]); fn test_merging_free_sections() {
let mut heap = Heap::empty(); let heap_vector = Box::new([0u8; HEAP_SIZE]);
heap.init( let mut heap = Heap::empty();
&heap_vector[0] as *const u8 as usize, heap.init(
&heap_vector[HEAP_SIZE - 1] as *const u8 as usize, &heap_vector[0] as *const u8 as usize,
&heap_vector[HEAP_SIZE - 1] as *const u8 as usize,
);
let root_header = heap.start_address;
let root_header_start_size = unsafe { (*root_header).size };
let malloc1 = heap.malloc(MIN_BLOCK_SIZE).unwrap();
let malloc_header_before = unsafe { *Heap::get_header_ref_from_data_pointer(malloc1) };
let malloc2 = heap.malloc(MIN_BLOCK_SIZE).unwrap();
let _ = heap.malloc(MIN_BLOCK_SIZE).unwrap();
unsafe {
assert!(heap.free(malloc1).is_ok());
let malloc_header_free = *Heap::get_header_ref_from_data_pointer(malloc1);
assert_ne!(malloc_header_before.free, malloc_header_free.free);
assert_eq!(malloc_header_before.size, malloc_header_free.size);
assert!(heap.free(malloc2).is_ok());
let malloc_header_merge = *Heap::get_header_ref_from_data_pointer(malloc1);
assert!(malloc_header_merge.free);
assert_eq!(
malloc_header_merge.size,
malloc_header_free.size + MIN_BLOCK_SIZE + HEAP_HEADER_SIZE
); );
}
let root_header = heap.start_address; }
let root_header_start_size = unsafe { (*root_header).size };
#[test]
let malloc1 = heap.malloc(MIN_BLOCK_SIZE).unwrap(); fn test_first_fit() {
let malloc_header_before = unsafe { *Heap::get_header_ref_from_data_pointer(malloc1) }; let heap_vector = Box::new([0u8; HEAP_SIZE]);
let malloc2 = heap.malloc(MIN_BLOCK_SIZE).unwrap(); let mut heap = Heap::empty();
let malloc3 = heap.malloc(MIN_BLOCK_SIZE).unwrap(); heap.init(
&heap_vector[0] as *const u8 as usize,
unsafe { &heap_vector[HEAP_SIZE - 1] as *const u8 as usize,
assert!(heap.free(malloc1).is_ok()); );
let malloc_header_free = *Heap::get_header_ref_from_data_pointer(malloc1); let root_header = heap.start_address;
assert_ne!(malloc_header_before.free, malloc_header_free.free); let root_header_start_size = unsafe { (*root_header).size };
assert_eq!(malloc_header_before.size, malloc_header_free.size);
let malloc1 = heap.malloc(MIN_BLOCK_SIZE).unwrap();
assert!(heap.free(malloc2).is_ok()); let malloc2 = heap.malloc(MIN_BLOCK_SIZE).unwrap();
let malloc_header_merge = *Heap::get_header_ref_from_data_pointer(malloc1); let malloc3 = heap.malloc(MIN_BLOCK_SIZE * 3).unwrap();
let malloc4 = heap.malloc(MIN_BLOCK_SIZE).unwrap();
assert!(malloc_header_merge.free);
assert_eq!( unsafe {
malloc_header_merge.size, assert!(heap.free(malloc1).is_ok());
malloc_header_free.size + MIN_BLOCK_SIZE + HEAP_HEADER_SIZE assert!(heap.free(malloc3).is_ok());
); let malloc5 = heap.malloc(MIN_BLOCK_SIZE * 2).unwrap();
} let malloc1_header = unsafe { *Heap::get_header_ref_from_data_pointer(malloc1) };
// First free block stays empty
assert!(malloc1_header.free);
// New allocation takes the first fit aka. malloc3
assert_eq!(malloc5, malloc3);
// If no free slot could be found, append to the end
let malloc6 = heap.malloc(MIN_BLOCK_SIZE * 2).unwrap();
assert!(malloc6 > malloc4);
// Malloc7 takes slot of Malloc1
let malloc7 = heap.malloc(MIN_BLOCK_SIZE).unwrap();
assert_eq!(malloc1, malloc7);
} }
} }