From 4c8b98703b2bb941af5f1dc476462027b6cf6cf6 Mon Sep 17 00:00:00 2001 From: yodalee Date: Wed, 25 Aug 2021 00:02:04 +0800 Subject: [PATCH] merge front/back padding after allocate current hole When we allocate a memory chunk, there may be some memory paddings in front/back of the allocated chunk. Before this change, these paddings are dealed by calling function deallocate. However the implementation is inefficient since deallocate function will search from the beginning of the linked-list and find the right place to insert these paddings. With this change, the paddings are linked to linked-list right after they are generated. We don't have to deal with merge continuous since paddings are guaranteed to be separated between them and to previous and next holes. --- src/hole.rs | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/hole.rs b/src/hole.rs index 8e57749..dfc6af5 100644 --- a/src/hole.rs +++ b/src/hole.rs @@ -92,16 +92,9 @@ impl HoleList { pub fn allocate_first_fit(&mut self, layout: Layout) -> Result<(NonNull, Layout), ()> { let aligned_layout = Self::align_layout(layout); - allocate_first_fit(&mut self.first, aligned_layout).map(|allocation| { - if let Some(padding) = allocation.front_padding { - deallocate(&mut self.first, padding.addr, padding.size); - } - if let Some(padding) = allocation.back_padding { - deallocate(&mut self.first, padding.addr, padding.size); - } - + allocate_first_fit(&mut self.first, aligned_layout).map(|holeinfo| { ( - NonNull::new(allocation.info.addr as *mut u8).unwrap(), + NonNull::new(holeinfo.addr as *mut u8).unwrap(), aligned_layout, ) }) @@ -242,13 +235,12 @@ fn split_hole(hole: HoleInfo, required_layout: Layout) -> Option { } /// Searches the list starting at the next hole of `previous` for a big enough hole. A hole is big -/// enough if it can hold an allocation of `layout.size()` bytes with the given `layou.align()`. +/// enough if it can hold an allocation of `layout.size()` bytes with the given `layout.align()`. /// When a hole is used for an allocation, there may be some needed padding before and/or after -/// the allocation. This padding is returned as part of the `Allocation`. The caller must take -/// care of freeing it again. +/// the allocation. The padding will then merge back to linked-list /// This function uses the “first fit” strategy, so it breaks as soon as a big enough hole is /// found (and returns it). -fn allocate_first_fit(mut previous: &mut Hole, layout: Layout) -> Result { +fn allocate_first_fit(mut previous: &mut Hole, layout: Layout) -> Result { loop { let allocation: Option = previous .next @@ -256,9 +248,34 @@ fn allocate_first_fit(mut previous: &mut Hole, layout: Layout) -> Result { - // hole is big enough, so remove it from the list by updating the previous pointer + // link the front/back padding + // Note that there must be no hole between following pair: + // previous - front_padding + // front_padding - back_padding + // back_padding - previous.next previous.next = previous.next.as_mut().unwrap().next.take(); - return Ok(allocation); + if let Some(padding) = allocation.front_padding { + let ptr = padding.addr as *mut Hole; + unsafe { + ptr.write (Hole { + size: padding.size, + next: previous.next.take(), + }) + } + previous.next = Some(unsafe { &mut *ptr }); + previous = move_helper(previous).next.as_mut().unwrap(); + } + if let Some(padding) = allocation.back_padding { + let ptr = padding.addr as *mut Hole; + unsafe { + ptr.write (Hole { + size: padding.size, + next: previous.next.take(), + }) + } + previous.next = Some(unsafe { &mut *ptr }); + } + return Ok(allocation.info); } None if previous.next.is_some() => { // try next hole