@@ -3,11 +3,13 @@ use core::mem::{self, size_of};
33
44use super :: align_up;
55
6+ /// A sorted list of holes. It uses the the holes itself to store its nodes.
67pub struct HoleList {
78 first : Hole , // dummy
89}
910
1011impl HoleList {
12+ /// Creates an empty `HoleList`.
1113 pub const fn empty ( ) -> HoleList {
1214 HoleList {
1315 first : Hole {
@@ -17,6 +19,9 @@ impl HoleList {
1719 }
1820 }
1921
22+ /// Creates a `HoleList` that contains the given hole. This function is unsafe because it
23+ /// creates a hole at the given `hole_addr`. This can cause undefined behavior if this address
24+ /// is invalid or if memory from the `[hole_addr, hole_addr+size) range is used somewhere else.
2025 pub unsafe fn new ( hole_addr : usize , hole_size : usize ) -> HoleList {
2126 assert ! ( size_of:: <Hole >( ) == Self :: min_size( ) ) ;
2227
@@ -35,6 +40,11 @@ impl HoleList {
3540 }
3641 }
3742
43+ /// Searches the list for a big enough hole. A hole is big enough if it can hold an allocation
44+ /// of `size` bytes with the given `align`. If such a hole is found in the list, a block of the
45+ /// required size is allocated from it. Then the start address of that block is returned.
46+ /// This function uses the “first fit” strategy, so it uses the first hole that is big enough.
47+ /// Thus the runtime is in O(n) but it should be reasonably fast for small allocations.
3848 pub fn allocate_first_fit ( & mut self , size : usize , align : usize ) -> Option < * mut u8 > {
3949 assert ! ( size >= Self :: min_size( ) ) ;
4050
@@ -49,14 +59,22 @@ impl HoleList {
4959 } )
5060 }
5161
62+ /// Frees the allocation given by `ptr` and `size`. `ptr` must be a pointer returned by a call
63+ /// to the `allocate_first_fit` function with identical size. Undefined behavior may occur for
64+ /// invalid arguments.
65+ /// This function walks the list and inserts the given block at the correct place. If the freed
66+ /// block is adjacent to another free block, the blocks are merged again.
67+ /// This operation is in `O(n)` since the list needs to be sorted by address.
5268 pub unsafe fn deallocate ( & mut self , ptr : * mut u8 , size : usize ) {
5369 deallocate ( & mut self . first , ptr as usize , size)
5470 }
5571
72+ /// Returns the minimal allocation size. Smaller allocations or deallocations are not allowed.
5673 pub fn min_size ( ) -> usize {
5774 size_of :: < usize > ( ) * 2
5875 }
5976
77+ /// Returns information about the first hole for test purposes.
6078 #[ cfg( test) ]
6179 pub fn first_hole ( & self ) -> Option < ( usize , usize ) > {
6280 self . first . next . as_ref ( ) . map ( |hole| ( * * hole as usize , unsafe { hole. get ( ) . size } ) )
@@ -77,6 +95,7 @@ pub struct Hole {
7795}
7896
7997impl Hole {
98+ /// Returns basic information about the hole.
8099 fn info ( & self ) -> HoleInfo {
81100 HoleInfo {
82101 addr : self as * const _ as usize ,
@@ -105,6 +124,11 @@ struct Allocation {
105124 back_padding : Option < HoleInfo > ,
106125}
107126
127+ /// Splits the given hole into `(front_padding, hole, back_padding)` if it's big enough to allocate
128+ /// `required_size` bytes with the `required_align`. Else `None` is returned.
129+ /// Front padding occurs if the required alignment is higher than the hole's alignment. Back
130+ /// padding occurs if the required size is smaller than the size of the aligned hole. All padding
131+ /// must be at least `HoleList::min_size()` big or the hole is unusable.
108132fn split_hole ( hole : HoleInfo , required_size : usize , required_align : usize ) -> Option < Allocation > {
109133 let aligned_hole = {
110134 let aligned_hole_addr = align_up ( hole. addr , required_align) ;
@@ -156,6 +180,12 @@ fn split_hole(hole: HoleInfo, required_size: usize, required_align: usize) -> Op
156180 } )
157181}
158182
183+ /// Searches the list starting at the next hole of `previous` for a big enough hole. A hole is big
184+ /// enough if it can hold an allocation of `size` bytes with the given `align`. When a hole is used
185+ /// for an allocation, there may be some needed padding before and/or after the allocation. This
186+ /// padding is returned as part of the `Allocation`. The caller must take care of freeing it again.
187+ /// This function uses the “first fit” strategy, so it breaks as soon as a big enough hole is found
188+ /// (and returns it).
159189fn allocate_first_fit ( previous : & mut Hole , size : usize , align : usize ) -> Option < Allocation > {
160190 previous. next
161191 . as_mut ( )
0 commit comments