Skip to content

Commit 420a993

Browse files
committed
Make it possible to extend the size of the heap
Add extend call that will increase the size of the heap by the given size. This is unsafe call and the caller must ensure that the new area is valid. That allows heap to be more memory efficient, consuming more memory only when necessary, eg. os allocator might map additional virtual memory when the allocation fails.
1 parent f70c60e commit 420a993

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

src/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,22 @@ impl Heap {
9393
pub fn size(&self) -> usize {
9494
self.size
9595
}
96+
97+
/// Return the top address of the heap
98+
pub fn top(&self) -> usize {
99+
self.bottom + self.size
100+
}
101+
102+
/// Extends the size of the heap by creating a new hole at the end
103+
///
104+
/// # Unsafety
105+
///
106+
/// The new extended area must be valid
107+
pub unsafe fn extend(&mut self, by: usize) {
108+
let top = self.top();
109+
self.holes.deallocate(top as *mut u8, by);
110+
self.size += by;
111+
}
96112
}
97113

98114
/// Align downwards. Returns the greatest x with alignment `align`

src/test.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ fn new_heap() -> Heap {
1212
heap
1313
}
1414

15+
fn new_max_heap() -> Heap {
16+
const HEAP_SIZE: usize = 1024;
17+
const HEAP_SIZE_MAX: usize = 2048;
18+
let heap_space = Box::into_raw(Box::new([0u8; HEAP_SIZE_MAX]));
19+
20+
let heap = unsafe { Heap::new(heap_space as usize, HEAP_SIZE) };
21+
assert!(heap.bottom == heap_space as usize);
22+
assert!(heap.size == HEAP_SIZE);
23+
heap
24+
}
25+
1526
#[test]
1627
fn empty() {
1728
let mut heap = Heap::empty();
@@ -201,3 +212,51 @@ fn align_from_small_to_big() {
201212
// try to allocate a 8 byte aligned block
202213
assert!(heap.allocate_first_fit(8, 8).is_some());
203214
}
215+
216+
#[test]
217+
fn extend_empty_heap() {
218+
let mut heap = new_max_heap();
219+
220+
unsafe {
221+
heap.extend(1024);
222+
}
223+
224+
// Try to allocate full heap after extend
225+
assert!(heap.allocate_first_fit(2048, 1).is_some());
226+
}
227+
228+
#[test]
229+
fn extend_full_heap() {
230+
let mut heap = new_max_heap();
231+
232+
// Allocate full heap, extend and allocate again to the max
233+
assert!(heap.allocate_first_fit(1024, 1).is_some());
234+
unsafe {
235+
heap.extend(1024);
236+
}
237+
assert!(heap.allocate_first_fit(1024, 1).is_some());
238+
}
239+
240+
#[test]
241+
fn extend_fragmented_heap() {
242+
let mut heap = new_max_heap();
243+
244+
let alloc1 = heap.allocate_first_fit(512, 1);
245+
let alloc2 = heap.allocate_first_fit(512, 1);
246+
247+
assert!(alloc1.is_some());
248+
assert!(alloc2.is_some());
249+
250+
unsafe {
251+
// Create a hole at the beginning of the heap
252+
heap.deallocate(alloc1.unwrap(), 512, 1);
253+
}
254+
255+
unsafe {
256+
heap.extend(1024);
257+
}
258+
259+
// We got additional 1024 bytes hole at the end of the heap
260+
// Try to allocate there
261+
assert!(heap.allocate_first_fit(1024, 1).is_some());
262+
}

0 commit comments

Comments
 (0)