Skip to content

Commit 2b38898

Browse files
Made hole module public for external uses (#47)
1 parent ad5beee commit 2b38898

File tree

2 files changed

+47
-31
lines changed

2 files changed

+47
-31
lines changed

src/hole.rs

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use core::alloc::Layout;
2+
use core::mem;
23
use core::mem::{align_of, size_of};
34
use core::ptr::NonNull;
45

@@ -55,34 +56,62 @@ impl HoleList {
5556
}
5657
}
5758

59+
/// Align layout. Returns a layout with size increased to
60+
/// fit at least `HoleList::min_size` and proper alignment of a `Hole`.
61+
pub fn align_layout(layout: Layout) -> Layout {
62+
let mut size = layout.size();
63+
if size < Self::min_size() {
64+
size = Self::min_size();
65+
}
66+
let size = align_up(size, mem::align_of::<Hole>());
67+
let layout = Layout::from_size_align(size, layout.align()).unwrap();
68+
69+
layout
70+
}
71+
5872
/// Searches the list for a big enough hole. A hole is big enough if it can hold an allocation
5973
/// of `layout.size()` bytes with the given `layout.align()`. If such a hole is found in the
6074
/// list, a block of the required size is allocated from it. Then the start address of that
61-
/// block is returned.
75+
/// block and the aligned layout are returned. The automatic layout alignment is required
76+
/// because the HoleList has some additional layout requirements for each memory block.
6277
/// This function uses the “first fit” strategy, so it uses the first hole that is big
6378
/// enough. Thus the runtime is in O(n) but it should be reasonably fast for small allocations.
64-
pub fn allocate_first_fit(&mut self, layout: Layout) -> Result<NonNull<u8>, ()> {
65-
assert!(layout.size() >= Self::min_size());
79+
pub fn allocate_first_fit(&mut self, layout: Layout) -> Result<(NonNull<u8>, Layout), ()> {
80+
let aligned_layout = Self::align_layout(layout);
6681

67-
allocate_first_fit(&mut self.first, layout).map(|allocation| {
82+
allocate_first_fit(&mut self.first, aligned_layout).map(|allocation| {
6883
if let Some(padding) = allocation.front_padding {
6984
deallocate(&mut self.first, padding.addr, padding.size);
7085
}
7186
if let Some(padding) = allocation.back_padding {
7287
deallocate(&mut self.first, padding.addr, padding.size);
7388
}
74-
NonNull::new(allocation.info.addr as *mut u8).unwrap()
89+
90+
(
91+
NonNull::new(allocation.info.addr as *mut u8).unwrap(),
92+
aligned_layout,
93+
)
7594
})
7695
}
7796

7897
/// Frees the allocation given by `ptr` and `layout`. `ptr` must be a pointer returned by a call
7998
/// to the `allocate_first_fit` function with identical layout. Undefined behavior may occur for
8099
/// invalid arguments.
100+
/// The function performs exactly the same layout adjustments as [allocate_first_fit] and
101+
/// returns the aligned layout.
81102
/// This function walks the list and inserts the given block at the correct place. If the freed
82103
/// block is adjacent to another free block, the blocks are merged again.
83104
/// This operation is in `O(n)` since the list needs to be sorted by address.
84-
pub unsafe fn deallocate(&mut self, ptr: NonNull<u8>, layout: Layout) {
85-
deallocate(&mut self.first, ptr.as_ptr() as usize, layout.size())
105+
///
106+
/// [allocate_first_fit]: ./struct.HoleList.html#method.allocate_first_fit
107+
pub unsafe fn deallocate(&mut self, ptr: NonNull<u8>, layout: Layout) -> Layout {
108+
let aligned_layout = Self::align_layout(layout);
109+
deallocate(
110+
&mut self.first,
111+
ptr.as_ptr() as usize,
112+
aligned_layout.size(),
113+
);
114+
aligned_layout
86115
}
87116

88117
/// Returns the minimal allocation size. Smaller allocations or deallocations are not allowed.

src/lib.rs

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,16 @@ use core::alloc::GlobalAlloc;
1717
use core::alloc::Layout;
1818
#[cfg(feature = "alloc_ref")]
1919
use core::alloc::{AllocError, Allocator};
20-
use core::mem;
2120
#[cfg(feature = "use_spin")]
2221
use core::ops::Deref;
2322
use core::ptr::NonNull;
24-
use hole::{Hole, HoleList};
23+
#[cfg(test)]
24+
use hole::Hole;
25+
use hole::HoleList;
2526
#[cfg(feature = "use_spin")]
2627
use spinning_top::Spinlock;
2728

28-
mod hole;
29+
pub mod hole;
2930
#[cfg(test)]
3031
mod test;
3132

@@ -89,31 +90,19 @@ impl Heap {
8990
}
9091
}
9192

92-
/// Align layout. Returns a layout with size increased to
93-
/// fit at least `HoleList::min_size` and proper alignment of a `Hole`.
94-
fn align_layout(layout: Layout) -> Layout {
95-
let mut size = layout.size();
96-
if size < HoleList::min_size() {
97-
size = HoleList::min_size();
98-
}
99-
let size = align_up(size, mem::align_of::<Hole>());
100-
let layout = Layout::from_size_align(size, layout.align()).unwrap();
101-
102-
layout
103-
}
104-
10593
/// Allocates a chunk of the given size with the given alignment. Returns a pointer to the
10694
/// beginning of that chunk if it was successful. Else it returns `None`.
10795
/// This function scans the list of free memory blocks and uses the first block that is big
10896
/// enough. The runtime is in O(n) where n is the number of free blocks, but it should be
10997
/// reasonably fast for small allocations.
11098
pub fn allocate_first_fit(&mut self, layout: Layout) -> Result<NonNull<u8>, ()> {
111-
let aligned_layout = Self::align_layout(layout);
112-
let res = self.holes.allocate_first_fit(aligned_layout);
113-
if res.is_ok() {
114-
self.used += aligned_layout.size();
99+
match self.holes.allocate_first_fit(layout) {
100+
Ok((ptr, aligned_layout)) => {
101+
self.used += aligned_layout.size();
102+
Ok(ptr)
103+
}
104+
Err(err) => Err(err),
115105
}
116-
res
117106
}
118107

119108
/// Frees the given allocation. `ptr` must be a pointer returned
@@ -124,9 +113,7 @@ impl Heap {
124113
/// correct place. If the freed block is adjacent to another free block, the blocks are merged
125114
/// again. This operation is in `O(n)` since the list needs to be sorted by address.
126115
pub unsafe fn deallocate(&mut self, ptr: NonNull<u8>, layout: Layout) {
127-
let aligned_layout = Self::align_layout(layout);
128-
self.holes.deallocate(ptr, aligned_layout);
129-
self.used -= aligned_layout.size();
116+
self.used -= self.holes.deallocate(ptr, layout).size();
130117
}
131118

132119
/// Returns the bottom address of the heap.

0 commit comments

Comments
 (0)