Skip to content

Commit d185357

Browse files
committed
Improve deallocate function with next_unwrap() and HoleInfo
1 parent 4e81e4a commit d185357

File tree

1 file changed

+31
-21
lines changed

1 file changed

+31
-21
lines changed

src/hole.rs

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -169,52 +169,60 @@ fn allocate_first_fit(previous: &mut Hole, size: usize, align: usize) -> Option<
169169
})
170170
}
171171

172+
/// Frees the allocation given by `(addr, size)`. It starts at the given hole and walks the list to
173+
/// find the correct place (the list is sorted by address).
172174
fn deallocate(hole: &mut Hole, addr: usize, size: usize) {
175+
assert!(size >= HoleList::min_size());
176+
173177
let hole_addr = if hole.size == 0 {
174-
0 // dummy
178+
// It's the dummy hole, which is the head of the HoleList. It's somewhere on the stack,
179+
// so it's address is not the address of the hole. We set the addr to 0 as it's always
180+
// the first hole.
181+
0
175182
} else {
183+
// tt's a real hole in memory and its address is the address of the hole
176184
hole as *mut _ as usize
177185
};
178-
assert!(addr >= hole_addr + hole.size);
179186

187+
// Each freed block must be handled by the previous hole in memory. Thus the freed address must
188+
// be always behind the current hole.
189+
assert!(hole_addr + hole.size <= addr);
180190

191+
// get information about the next block
192+
let next_hole_info = hole.next.as_ref().map(|next| unsafe { next.get().info() });
181193

182-
match mem::replace(&mut hole.next, None) {
183-
Some(ref mut next) if addr == hole_addr + hole.size && addr + size == **next as usize => {
194+
match next_hole_info {
195+
Some(next) if hole_addr + hole.size == addr && addr + size == next.addr => {
184196
// block fills the gap between this hole and the next hole
185197
// before: ___XXX____YYYYY____ where X is this hole and Y the next hole
186198
// after: ___XXXFFFFYYYYY____ where F is the freed block
187-
hole.size += size + unsafe { next.get().size };
188-
hole.next = unsafe { next.get_mut() }.next.take();
199+
200+
hole.size += size + next.size; // merge the F and Y blocks to this X block
201+
hole.next = hole.next_unwrap().next.take(); // remove the Y block
189202
}
190-
Some(ref next) if addr == hole_addr + hole.size => {
203+
Some(_) if hole_addr + hole.size == addr => {
191204
// block is right behind this hole but there is used memory after it
192205
// before: ___XXX______YYYYY____ where X is this hole and Y the next hole
193206
// after: ___XXXFFFF__YYYYY____ where F is the freed block
194-
hole.size += size;
195207

196-
// hole.next should stay the same
197-
hole.next = Some(unsafe { Unique::new(**next) }); //hack to avoid implementing clone
208+
hole.size += size; // merge the F block to this X block
198209
}
199-
Some(ref mut next) if addr + size == **next as usize => {
210+
Some(next) if addr + size == next.addr => {
200211
// block is right before the next hole but there is used memory before it
201212
// before: ___XXX______YYYYY____ where X is this hole and Y the next hole
202213
// after: ___XXX__FFFFYYYYY____ where F is the freed block
203-
let next_hole_next = unsafe { next.get_mut() }.next.take();
204-
let next_hole_size = unsafe { next.get() }.size;
205-
hole.next = next_hole_next; // delete next block
206-
deallocate(hole, addr, size + next_hole_size); // free it again as a big block
214+
215+
hole.next = hole.next_unwrap().next.take(); // remove the Y block
216+
deallocate(hole, addr, size + next.size); // free the merged F/Y block
207217
}
208-
Some(ref mut next) if addr >= **next as usize => {
218+
Some(next) if next.addr <= addr => {
209219
// block is behind the next hole, so we delegate it to the next hole
210220
// before: ___XXX__YYYYY________ where X is this hole and Y the next hole
211221
// after: ___XXX__YYYYY__FFFF__ where F is the freed block
212222

213-
// hole.next should stay the same
214-
hole.next = Some(unsafe { Unique::new(**next) }); // hack to avoid implementing clone
215-
deallocate(unsafe { next.get_mut() }, addr, size);
223+
deallocate(hole.next_unwrap(), addr, size);
216224
}
217-
next => {
225+
_ => {
218226
// block is between this and the next hole
219227
// before: ___XXX________YYYYY_ where X is this hole and Y the next hole
220228
// after: ___XXX__FFFF__YYYYY_ where F is the freed block
@@ -225,10 +233,12 @@ fn deallocate(hole: &mut Hole, addr: usize, size: usize) {
225233

226234
let new_hole = Hole {
227235
size: size,
228-
next: next,
236+
next: hole.next.take(), // the reference to the Y block (if it exists)
229237
};
238+
// write the new hole to the freed memory
230239
let ptr = addr as *mut Hole;
231240
mem::forget(mem::replace(unsafe { &mut *ptr }, new_hole));
241+
// add the F block as the next block of the X block
232242
hole.next = Some(unsafe { Unique::new(ptr) });
233243
}
234244
}

0 commit comments

Comments
 (0)