Skip to content

Commit 7dc809f

Browse files
authored
Merge pull request #3 from rafalmiel/heap_extend
Make it possible to extend the size of the heap
2 parents 9a3bb89 + 24db8fd commit 7dc809f

File tree

3 files changed

+86
-7
lines changed

3 files changed

+86
-7
lines changed

src/hole.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ impl HoleList {
2626
assert!(size_of::<Hole>() == Self::min_size());
2727

2828
let ptr = hole_addr as *mut Hole;
29-
mem::forget(mem::replace(&mut *ptr,
30-
Hole {
31-
size: hole_size,
32-
next: None,
33-
}));
29+
mem::replace(&mut *ptr,
30+
Hole {
31+
size: hole_size,
32+
next: None,
33+
});
3434

3535
HoleList {
3636
first: Hole {
@@ -240,11 +240,15 @@ fn deallocate(mut hole: &mut Hole, addr: usize, mut size: usize) {
240240
hole.size += size + next.size; // merge the F and Y blocks to this X block
241241
hole.next = hole.next_unwrap().next.take(); // remove the Y block
242242
}
243-
Some(_) if hole_addr + hole.size == addr => {
243+
_ if hole_addr + hole.size == addr => {
244244
// block is right behind this hole but there is used memory after it
245245
// before: ___XXX______YYYYY____ where X is this hole and Y the next hole
246246
// after: ___XXXFFFF__YYYYY____ where F is the freed block
247247

248+
// or: block is right behind this hole and this is the last hole
249+
// before: ___XXX_______________ where X is this hole and Y the next hole
250+
// after: ___XXXFFFF___________ where F is the freed block
251+
248252
hole.size += size; // merge the F block to this X block
249253
}
250254
Some(next) if addr + size == next.addr => {
@@ -279,7 +283,7 @@ fn deallocate(mut hole: &mut Hole, addr: usize, mut size: usize) {
279283
};
280284
// write the new hole to the freed memory
281285
let ptr = addr as *mut Hole;
282-
mem::forget(mem::replace(unsafe { &mut *ptr }, new_hole));
286+
mem::replace(unsafe { &mut *ptr }, new_hole);
283287
// add the F block as the next block of the X block
284288
hole.next = Some(unsafe { Unique::new(ptr) });
285289
}

src/lib.rs

+16
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

+59
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)