1
1
use core:: ptr:: Unique ;
2
2
use core:: mem:: { self , size_of} ;
3
+ use alloc:: allocator:: { Layout , AllocErr } ;
3
4
4
5
use super :: align_up;
5
6
@@ -41,14 +42,15 @@ impl HoleList {
41
42
}
42
43
43
44
/// 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.
45
+ /// of `layout.size()` bytes with the given `layout.align()`. If such a hole is found in the
46
+ /// list, a block of the required size is allocated from it. Then the start address of that
47
+ /// block is returned.
46
48
/// This function uses the “first fit” strategy, so it uses the first hole that is big
47
49
/// enough. Thus the runtime is in O(n) but it should be reasonably fast for small allocations.
48
- pub fn allocate_first_fit ( & mut self , size : usize , align : usize ) -> Option < * mut u8 > {
49
- assert ! ( size >= Self :: min_size( ) ) ;
50
+ pub fn allocate_first_fit ( & mut self , layout : Layout ) -> Result < * mut u8 , AllocErr > {
51
+ assert ! ( layout . size( ) >= Self :: min_size( ) ) ;
50
52
51
- allocate_first_fit ( & mut self . first , size , align ) . map ( |allocation| {
53
+ allocate_first_fit ( & mut self . first , layout ) . map ( |allocation| {
52
54
if let Some ( padding) = allocation. front_padding {
53
55
deallocate ( & mut self . first , padding. addr , padding. size ) ;
54
56
}
@@ -59,14 +61,14 @@ impl HoleList {
59
61
} )
60
62
}
61
63
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
+ /// Frees the allocation given by `ptr` and `layout `. `ptr` must be a pointer returned by a call
65
+ /// to the `allocate_first_fit` function with identical layout . Undefined behavior may occur for
64
66
/// invalid arguments.
65
67
/// This function walks the list and inserts the given block at the correct place. If the freed
66
68
/// block is adjacent to another free block, the blocks are merged again.
67
69
/// This operation is in `O(n)` since the list needs to be sorted by address.
68
- pub unsafe fn deallocate ( & mut self , ptr : * mut u8 , size : usize ) {
69
- deallocate ( & mut self . first , ptr as usize , size)
70
+ pub unsafe fn deallocate ( & mut self , ptr : * mut u8 , layout : Layout ) {
71
+ deallocate ( & mut self . first , ptr as usize , layout . size ( ) )
70
72
}
71
73
72
74
/// Returns the minimal allocation size. Smaller allocations or deallocations are not allowed.
@@ -125,11 +127,14 @@ struct Allocation {
125
127
}
126
128
127
129
/// 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.
130
+ /// `required_layout.size() ` bytes with the `required_layout.align() `. Else `None` is returned.
129
131
/// Front padding occurs if the required alignment is higher than the hole's alignment. Back
130
132
/// padding occurs if the required size is smaller than the size of the aligned hole. All padding
131
133
/// must be at least `HoleList::min_size()` big or the hole is unusable.
132
- fn split_hole ( hole : HoleInfo , required_size : usize , required_align : usize ) -> Option < Allocation > {
134
+ fn split_hole ( hole : HoleInfo , required_layout : Layout ) -> Option < Allocation > {
135
+ let required_size = required_layout. size ( ) ;
136
+ let required_align = required_layout. align ( ) ;
137
+
133
138
let ( aligned_addr, front_padding) = if hole. addr == align_up ( hole. addr , required_align) {
134
139
// hole has already the required alignment
135
140
( hole. addr , None )
@@ -184,24 +189,26 @@ fn split_hole(hole: HoleInfo, required_size: usize, required_align: usize) -> Op
184
189
/// padding is returned as part of the `Allocation`. The caller must take care of freeing it again.
185
190
/// This function uses the “first fit” strategy, so it breaks as soon as a big enough hole is
186
191
/// found (and returns it).
187
- fn allocate_first_fit ( mut previous : & mut Hole , size : usize , align : usize ) -> Option < Allocation > {
192
+ fn allocate_first_fit ( mut previous : & mut Hole , layout : Layout ) -> Result < Allocation , AllocErr > {
188
193
loop {
189
194
let allocation: Option < Allocation > = previous. next
190
195
. as_mut ( )
191
- . and_then ( |current| split_hole ( unsafe { current. as_ref ( ) } . info ( ) , size , align ) ) ;
196
+ . and_then ( |current| split_hole ( unsafe { current. as_ref ( ) } . info ( ) , layout . clone ( ) ) ) ;
192
197
match allocation {
193
198
Some ( allocation) => {
194
199
// hole is big enough, so remove it from the list by updating the previous pointer
195
200
previous. next = previous. next_unwrap ( ) . next . take ( ) ;
196
- return Some ( allocation) ;
201
+ return Ok ( allocation) ;
197
202
}
198
203
None if previous. next . is_some ( ) => {
199
204
// try next hole
200
205
previous = move_helper ( previous) . next_unwrap ( ) ;
201
206
}
202
207
None => {
203
208
// this was the last hole, so no hole is big enough -> allocation not possible
204
- return None ;
209
+ return Err ( AllocErr :: Exhausted {
210
+ request : layout,
211
+ } ) ;
205
212
}
206
213
}
207
214
}
0 commit comments