From 69fc4cf0a0a557c6e32f669b432a9635f485c0cf Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 28 Dec 2020 15:32:19 +0100 Subject: [PATCH 01/10] Made hole.rs public for external uses. Moved `align_layout()` function into `HoleList` --- src/hole.rs | 15 +++++++++++++++ src/lib.rs | 22 ++++------------------ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/hole.rs b/src/hole.rs index a1db1c5..0f5abfa 100644 --- a/src/hole.rs +++ b/src/hole.rs @@ -3,6 +3,7 @@ use core::mem::{align_of, size_of}; use core::ptr::NonNull; use super::align_up; +use core::mem; /// A sorted list of holes. It uses the the holes itself to store its nodes. pub struct HoleList { @@ -55,6 +56,20 @@ impl HoleList { } } + + /// Align layout. Returns a layout with size increased to + /// fit at least `HoleList::min_size` and proper alignment of a `Hole`. + pub fn align_layout(layout: Layout) -> Layout { + let mut size = layout.size(); + if size < Self::min_size() { + size = Self::min_size(); + } + let size = align_up(size, mem::align_of::()); + let layout = Layout::from_size_align(size, layout.align()).unwrap(); + + layout + } + /// Searches the list for a big enough hole. A hole is big enough if it can hold an allocation /// of `layout.size()` bytes with the given `layout.align()`. If such a hole is found in the /// list, a block of the required size is allocated from it. Then the start address of that diff --git a/src/lib.rs b/src/lib.rs index dbadb18..2a18e67 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,15 +17,14 @@ use core::alloc::GlobalAlloc; use core::alloc::Layout; #[cfg(feature = "alloc_ref")] use core::alloc::{AllocError, Allocator}; -use core::mem; #[cfg(feature = "use_spin")] use core::ops::Deref; use core::ptr::NonNull; -use hole::{Hole, HoleList}; +use hole::HoleList; #[cfg(feature = "use_spin")] use spinning_top::Spinlock; -mod hole; +pub mod hole; #[cfg(test)] mod test; @@ -89,26 +88,13 @@ impl Heap { } } - /// Align layout. Returns a layout with size increased to - /// fit at least `HoleList::min_size` and proper alignment of a `Hole`. - fn align_layout(layout: Layout) -> Layout { - let mut size = layout.size(); - if size < HoleList::min_size() { - size = HoleList::min_size(); - } - let size = align_up(size, mem::align_of::()); - let layout = Layout::from_size_align(size, layout.align()).unwrap(); - - layout - } - /// Allocates a chunk of the given size with the given alignment. Returns a pointer to the /// beginning of that chunk if it was successful. Else it returns `None`. /// This function scans the list of free memory blocks and uses the first block that is big /// enough. The runtime is in O(n) where n is the number of free blocks, but it should be /// reasonably fast for small allocations. pub fn allocate_first_fit(&mut self, layout: Layout) -> Result, ()> { - let aligned_layout = Self::align_layout(layout); + let aligned_layout = HoleList::align_layout(layout); let res = self.holes.allocate_first_fit(aligned_layout); if res.is_ok() { self.used += aligned_layout.size(); @@ -124,7 +110,7 @@ impl Heap { /// correct place. If the freed block is adjacent to another free block, the blocks are merged /// again. This operation is in `O(n)` since the list needs to be sorted by address. pub unsafe fn deallocate(&mut self, ptr: NonNull, layout: Layout) { - let aligned_layout = Self::align_layout(layout); + let aligned_layout = HoleList::align_layout(layout); self.holes.deallocate(ptr, aligned_layout); self.used -= aligned_layout.size(); } From b824676697ddbcec0b221cacc4480d5d817999ad Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 28 Dec 2020 15:50:47 +0100 Subject: [PATCH 02/10] Fixed missing import --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 2a18e67..e354361 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ use core::alloc::{AllocError, Allocator}; #[cfg(feature = "use_spin")] use core::ops::Deref; use core::ptr::NonNull; -use hole::HoleList; +use hole::{Hole, HoleList}; #[cfg(feature = "use_spin")] use spinning_top::Spinlock; From b2083a856c4a089e8656ffafd0eaac3fca4afa8d Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 28 Dec 2020 15:54:33 +0100 Subject: [PATCH 03/10] Fixed import warnings, reordered imports --- src/hole.rs | 4 ++-- src/lib.rs | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hole.rs b/src/hole.rs index 0f5abfa..7a290d7 100644 --- a/src/hole.rs +++ b/src/hole.rs @@ -1,9 +1,9 @@ use core::alloc::Layout; +use core::mem; use core::mem::{align_of, size_of}; -use core::ptr::NonNull; +use core::ptr::NonNull; use super::align_up; -use core::mem; /// A sorted list of holes. It uses the the holes itself to store its nodes. pub struct HoleList { diff --git a/src/lib.rs b/src/lib.rs index e354361..3b58bc9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,9 @@ use core::alloc::{AllocError, Allocator}; #[cfg(feature = "use_spin")] use core::ops::Deref; use core::ptr::NonNull; -use hole::{Hole, HoleList}; +use hole::HoleList; +#[cfg(test)] +use hole::Hole; #[cfg(feature = "use_spin")] use spinning_top::Spinlock; From de644e72020384e510261fcc4983ef085fb2ba6c Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 28 Dec 2020 16:00:20 +0100 Subject: [PATCH 04/10] Fixed formatting task --- src/hole.rs | 6 ++++-- src/lib.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hole.rs b/src/hole.rs index 7a290d7..b318c3d 100644 --- a/src/hole.rs +++ b/src/hole.rs @@ -1,8 +1,8 @@ use core::alloc::Layout; use core::mem; use core::mem::{align_of, size_of}; - use core::ptr::NonNull; + use super::align_up; /// A sorted list of holes. It uses the the holes itself to store its nodes. @@ -322,7 +322,9 @@ fn deallocate(mut hole: &mut Hole, addr: usize, mut size: usize) { // write the new hole to the freed memory debug_assert_eq!(addr % align_of::(), 0); let ptr = addr as *mut Hole; - unsafe { ptr.write(new_hole) }; + unsafe { + ptr.write(new_hole) + }; // add the F block as the next block of the X block hole.next = Some(unsafe { &mut *ptr }); } diff --git a/src/lib.rs b/src/lib.rs index 3b58bc9..27d0304 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,9 +20,9 @@ use core::alloc::{AllocError, Allocator}; #[cfg(feature = "use_spin")] use core::ops::Deref; use core::ptr::NonNull; -use hole::HoleList; #[cfg(test)] use hole::Hole; +use hole::HoleList; #[cfg(feature = "use_spin")] use spinning_top::Spinlock; From 91e179258b51244cd091275b5c64da88a52cf894 Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 28 Dec 2020 16:02:53 +0100 Subject: [PATCH 05/10] Fixed formatting task --- src/hole.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/hole.rs b/src/hole.rs index b318c3d..5dc1724 100644 --- a/src/hole.rs +++ b/src/hole.rs @@ -56,7 +56,6 @@ impl HoleList { } } - /// Align layout. Returns a layout with size increased to /// fit at least `HoleList::min_size` and proper alignment of a `Hole`. pub fn align_layout(layout: Layout) -> Layout { @@ -322,9 +321,7 @@ fn deallocate(mut hole: &mut Hole, addr: usize, mut size: usize) { // write the new hole to the freed memory debug_assert_eq!(addr % align_of::(), 0); let ptr = addr as *mut Hole; - unsafe { - ptr.write(new_hole) - }; + unsafe { ptr.write(new_hole) }; // add the F block as the next block of the X block hole.next = Some(unsafe { &mut *ptr }); } From e1452722904d7c24fd4972d1ef4c134db08b1704 Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 28 Dec 2020 16:18:28 +0100 Subject: [PATCH 06/10] Moved `align_layout` calls into `HoleList` --- src/hole.rs | 14 ++++++++------ src/lib.rs | 11 ++++------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/hole.rs b/src/hole.rs index 5dc1724..c879e8d 100644 --- a/src/hole.rs +++ b/src/hole.rs @@ -75,17 +75,17 @@ impl HoleList { /// block is returned. /// This function uses the “first fit” strategy, so it uses the first hole that is big /// enough. Thus the runtime is in O(n) but it should be reasonably fast for small allocations. - pub fn allocate_first_fit(&mut self, layout: Layout) -> Result, ()> { - assert!(layout.size() >= Self::min_size()); + pub fn allocate_first_fit(&mut self, layout: Layout) -> Result<(NonNull, Layout), ()> { + let aligned_layout = Self::align_layout(layout); - allocate_first_fit(&mut self.first, layout).map(|allocation| { + allocate_first_fit(&mut self.first, aligned_layout).map(|allocation| { if let Some(padding) = allocation.front_padding { deallocate(&mut self.first, padding.addr, padding.size); } if let Some(padding) = allocation.back_padding { deallocate(&mut self.first, padding.addr, padding.size); } - NonNull::new(allocation.info.addr as *mut u8).unwrap() + (NonNull::new(allocation.info.addr as *mut u8).unwrap(), aligned_layout) }) } @@ -95,8 +95,10 @@ impl HoleList { /// This function walks the list and inserts the given block at the correct place. If the freed /// block is adjacent to another free block, the blocks are merged again. /// This operation is in `O(n)` since the list needs to be sorted by address. - pub unsafe fn deallocate(&mut self, ptr: NonNull, layout: Layout) { - deallocate(&mut self.first, ptr.as_ptr() as usize, layout.size()) + pub unsafe fn deallocate(&mut self, ptr: NonNull, layout: Layout) -> Layout { + let aligned_layout = Self::align_layout(layout); + deallocate(&mut self.first, ptr.as_ptr() as usize, aligned_layout.size()); + aligned_layout } /// Returns the minimal allocation size. Smaller allocations or deallocations are not allowed. diff --git a/src/lib.rs b/src/lib.rs index 27d0304..edca906 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -96,12 +96,11 @@ impl Heap { /// enough. The runtime is in O(n) where n is the number of free blocks, but it should be /// reasonably fast for small allocations. pub fn allocate_first_fit(&mut self, layout: Layout) -> Result, ()> { - let aligned_layout = HoleList::align_layout(layout); - let res = self.holes.allocate_first_fit(aligned_layout); + let res = self.holes.allocate_first_fit(layout); if res.is_ok() { - self.used += aligned_layout.size(); + self.used += res.unwrap().1.size(); } - res + res.map(|tuple| tuple.0) } /// Frees the given allocation. `ptr` must be a pointer returned @@ -112,9 +111,7 @@ impl Heap { /// correct place. If the freed block is adjacent to another free block, the blocks are merged /// again. This operation is in `O(n)` since the list needs to be sorted by address. pub unsafe fn deallocate(&mut self, ptr: NonNull, layout: Layout) { - let aligned_layout = HoleList::align_layout(layout); - self.holes.deallocate(ptr, aligned_layout); - self.used -= aligned_layout.size(); + self.used -= self.holes.deallocate(ptr, layout).size(); } /// Returns the bottom address of the heap. From b6c84e96d1a88cfc3de2e53306c4b5930ed8936d Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 28 Dec 2020 16:20:45 +0100 Subject: [PATCH 07/10] Fixed formatting --- src/hole.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/hole.rs b/src/hole.rs index c879e8d..06b45f2 100644 --- a/src/hole.rs +++ b/src/hole.rs @@ -85,7 +85,11 @@ impl HoleList { if let Some(padding) = allocation.back_padding { deallocate(&mut self.first, padding.addr, padding.size); } - (NonNull::new(allocation.info.addr as *mut u8).unwrap(), aligned_layout) + + ( + NonNull::new(allocation.info.addr as *mut u8).unwrap(), + aligned_layout + ) }) } @@ -97,7 +101,11 @@ impl HoleList { /// This operation is in `O(n)` since the list needs to be sorted by address. pub unsafe fn deallocate(&mut self, ptr: NonNull, layout: Layout) -> Layout { let aligned_layout = Self::align_layout(layout); - deallocate(&mut self.first, ptr.as_ptr() as usize, aligned_layout.size()); + deallocate( + &mut self.first, + ptr.as_ptr() as usize, + aligned_layout.size() + ); aligned_layout } From 8c7692faca57f19927389e5b687ab1b72dbe8efe Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 28 Dec 2020 16:22:02 +0100 Subject: [PATCH 08/10] Fixed formatting --- src/hole.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hole.rs b/src/hole.rs index 06b45f2..8ebb0a8 100644 --- a/src/hole.rs +++ b/src/hole.rs @@ -88,7 +88,7 @@ impl HoleList { ( NonNull::new(allocation.info.addr as *mut u8).unwrap(), - aligned_layout + aligned_layout, ) }) } @@ -104,7 +104,7 @@ impl HoleList { deallocate( &mut self.first, ptr.as_ptr() as usize, - aligned_layout.size() + aligned_layout.size(), ); aligned_layout } From 4f6a0e5b264385349d3c9f5eb49e2ef298f32964 Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 28 Dec 2020 17:07:43 +0100 Subject: [PATCH 09/10] Updated docs, simplified `Heap::allocate_first_fit()` --- src/hole.rs | 7 ++++++- src/lib.rs | 10 ++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/hole.rs b/src/hole.rs index 8ebb0a8..07734c4 100644 --- a/src/hole.rs +++ b/src/hole.rs @@ -72,7 +72,8 @@ impl HoleList { /// Searches the list for a big enough hole. A hole is big enough if it can hold an allocation /// of `layout.size()` bytes with the given `layout.align()`. If such a hole is found in the /// list, a block of the required size is allocated from it. Then the start address of that - /// block is returned. + /// block and the aligned layout are returned. The automatic layout alignment is required + /// because the HoleList has some additional layout requirements for each memory block. /// This function uses the “first fit” strategy, so it uses the first hole that is big /// enough. Thus the runtime is in O(n) but it should be reasonably fast for small allocations. pub fn allocate_first_fit(&mut self, layout: Layout) -> Result<(NonNull, Layout), ()> { @@ -96,9 +97,13 @@ impl HoleList { /// Frees the allocation given by `ptr` and `layout`. `ptr` must be a pointer returned by a call /// to the `allocate_first_fit` function with identical layout. Undefined behavior may occur for /// invalid arguments. + /// The function performs exactly the same layout adjustments as [allocate_first_fit] and + /// returns the aligned layout. /// This function walks the list and inserts the given block at the correct place. If the freed /// block is adjacent to another free block, the blocks are merged again. /// This operation is in `O(n)` since the list needs to be sorted by address. + /// + /// [allocate_first_fit]: ./struct.HoleList.html#method.allocate_first_fit pub unsafe fn deallocate(&mut self, ptr: NonNull, layout: Layout) -> Layout { let aligned_layout = Self::align_layout(layout); deallocate( diff --git a/src/lib.rs b/src/lib.rs index edca906..78e38d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -96,11 +96,13 @@ impl Heap { /// enough. The runtime is in O(n) where n is the number of free blocks, but it should be /// reasonably fast for small allocations. pub fn allocate_first_fit(&mut self, layout: Layout) -> Result, ()> { - let res = self.holes.allocate_first_fit(layout); - if res.is_ok() { - self.used += res.unwrap().1.size(); + match self.holes.allocate_first_fit(layout) { + Ok((ptr, aligned_layout)) => { + self.used += aligned_layout.size(); + Ok(ptr) + }, + Err(err) => Err(err), } - res.map(|tuple| tuple.0) } /// Frees the given allocation. `ptr` must be a pointer returned From d78ef81dfac79f5a57846b63bd43ab98646034e0 Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 28 Dec 2020 17:09:01 +0100 Subject: [PATCH 10/10] Fixed formatting --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 78e38d5..e31cb96 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,7 +100,7 @@ impl Heap { Ok((ptr, aligned_layout)) => { self.used += aligned_layout.size(); Ok(ptr) - }, + } Err(err) => Err(err), } }