@@ -3,11 +3,13 @@ use core::mem::{self, size_of};
3
3
4
4
use super :: align_up;
5
5
6
+ /// A sorted list of holes. It uses the the holes itself to store its nodes.
6
7
pub struct HoleList {
7
8
first : Hole , // dummy
8
9
}
9
10
10
11
impl HoleList {
12
+ /// Creates an empty `HoleList`.
11
13
pub const fn empty ( ) -> HoleList {
12
14
HoleList {
13
15
first : Hole {
@@ -17,6 +19,9 @@ impl HoleList {
17
19
}
18
20
}
19
21
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.
20
25
pub unsafe fn new ( hole_addr : usize , hole_size : usize ) -> HoleList {
21
26
assert ! ( size_of:: <Hole >( ) == Self :: min_size( ) ) ;
22
27
@@ -35,6 +40,11 @@ impl HoleList {
35
40
}
36
41
}
37
42
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.
38
48
pub fn allocate_first_fit ( & mut self , size : usize , align : usize ) -> Option < * mut u8 > {
39
49
assert ! ( size >= Self :: min_size( ) ) ;
40
50
@@ -49,14 +59,22 @@ impl HoleList {
49
59
} )
50
60
}
51
61
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.
52
68
pub unsafe fn deallocate ( & mut self , ptr : * mut u8 , size : usize ) {
53
69
deallocate ( & mut self . first , ptr as usize , size)
54
70
}
55
71
72
+ /// Returns the minimal allocation size. Smaller allocations or deallocations are not allowed.
56
73
pub fn min_size ( ) -> usize {
57
74
size_of :: < usize > ( ) * 2
58
75
}
59
76
77
+ /// Returns information about the first hole for test purposes.
60
78
#[ cfg( test) ]
61
79
pub fn first_hole ( & self ) -> Option < ( usize , usize ) > {
62
80
self . first . next . as_ref ( ) . map ( |hole| ( * * hole as usize , unsafe { hole. get ( ) . size } ) )
@@ -77,6 +95,7 @@ pub struct Hole {
77
95
}
78
96
79
97
impl Hole {
98
+ /// Returns basic information about the hole.
80
99
fn info ( & self ) -> HoleInfo {
81
100
HoleInfo {
82
101
addr : self as * const _ as usize ,
@@ -105,6 +124,11 @@ struct Allocation {
105
124
back_padding : Option < HoleInfo > ,
106
125
}
107
126
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.
108
132
fn split_hole ( hole : HoleInfo , required_size : usize , required_align : usize ) -> Option < Allocation > {
109
133
let aligned_hole = {
110
134
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
156
180
} )
157
181
}
158
182
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).
159
189
fn allocate_first_fit ( previous : & mut Hole , size : usize , align : usize ) -> Option < Allocation > {
160
190
previous. next
161
191
. as_mut ( )
0 commit comments