Skip to content

Commit 4e81e4a

Browse files
committed
Further improve allocation function
1 parent 9d649ad commit 4e81e4a

File tree

1 file changed

+49
-44
lines changed

1 file changed

+49
-44
lines changed

src/hole.rs

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,15 @@ impl HoleList {
3737
pub fn allocate_first_fit(&mut self, size: usize, align: usize) -> Option<*mut u8> {
3838
assert!(size >= Self::min_size());
3939

40-
if let Some(result) = allocate_first_fit(&mut self.first, size, align) {
41-
if let Some(HoleInfo{addr: padding_addr, size: padding_size}) = result.front_padding {
42-
self.deallocate(padding_addr as *mut u8, padding_size);
40+
allocate_first_fit(&mut self.first, size, align).map(|allocation| {
41+
if let Some(padding) = allocation.front_padding {
42+
deallocate(&mut self.first, padding.addr, padding.size);
4343
}
44-
if let Some(HoleInfo{addr: padding_addr, size: padding_size}) = result.back_padding {
45-
self.deallocate(padding_addr as *mut u8, padding_size);
44+
if let Some(padding) = allocation.back_padding {
45+
deallocate(&mut self.first, padding.addr, padding.size);
4646
}
47-
Some(result.hole.addr as *mut u8)
48-
} else {
49-
None
50-
}
47+
allocation.info.addr as *mut u8
48+
})
5149
}
5250

5351
pub fn deallocate(&mut self, ptr: *mut u8, size: usize) {
@@ -83,20 +81,29 @@ impl Hole {
8381
size: self.size,
8482
}
8583
}
84+
85+
/// Returns a reference to the next hole. Panics if this is the last hole.
86+
fn next_unwrap(&mut self) -> &mut Hole {
87+
unsafe { self.next.as_mut().unwrap().get_mut() }
88+
}
8689
}
8790

91+
/// Basic information about a hole.
92+
#[derive(Debug, Clone, Copy)]
8893
struct HoleInfo {
8994
addr: usize,
9095
size: usize,
9196
}
9297

93-
struct HoleResult {
94-
hole: HoleInfo,
98+
/// The result returned by `split_hole` and `allocate_first_fit`. Contains the address and size of
99+
/// the allocation (in the `info` field), and the front and back padding.
100+
struct Allocation {
101+
info: HoleInfo,
95102
front_padding: Option<HoleInfo>,
96103
back_padding: Option<HoleInfo>,
97104
}
98105

99-
fn split_hole(hole: HoleInfo, required_size: usize, required_align: usize) -> Option<HoleResult> {
106+
fn split_hole(hole: HoleInfo, required_size: usize, required_align: usize) -> Option<Allocation> {
100107
let aligned_hole = {
101108
let aligned_hole_addr = align_up(hole.addr, required_align);
102109
if aligned_hole_addr + required_size > hole.addr + hole.size {
@@ -109,36 +116,36 @@ fn split_hole(hole: HoleInfo, required_size: usize, required_align: usize) -> Op
109116
}
110117
};
111118

112-
let front_padding = if aligned_hole.addr > hole.addr {
113-
if aligned_hole.addr < hole.addr + HoleList::min_size() {
114-
// hole would cause a new, too small hole
115-
return None;
116-
} else {
117-
Some(HoleInfo {
118-
addr: hole.addr,
119-
size: aligned_hole.addr - hole.addr,
120-
})
121-
}
122-
} else {
119+
let front_padding = if aligned_hole.addr == hole.addr {
120+
// hole has already the required alignment
123121
None
122+
} else if aligned_hole.addr < hole.addr + HoleList::min_size() {
123+
// we can't use this hole because the required padding would create a new, too small hole
124+
return None;
125+
} else {
126+
// the required alignment causes some padding before the allocation
127+
Some(HoleInfo {
128+
addr: hole.addr,
129+
size: aligned_hole.addr - hole.addr,
130+
})
124131
};
125132

126-
let back_padding = if aligned_hole.size > required_size {
127-
if aligned_hole.size - required_size < HoleList::min_size() {
128-
// hole would cause a new, too small hole
129-
return None;
130-
} else {
131-
Some(HoleInfo {
132-
addr: aligned_hole.addr + required_size,
133-
size: aligned_hole.size - required_size,
134-
})
135-
}
136-
} else {
133+
let back_padding = if aligned_hole.size == required_size {
134+
// the aligned hole has exactly the size that's needed, no padding accrues
137135
None
136+
} else if aligned_hole.size - required_size < HoleList::min_size() {
137+
// we can't use this hole since its remains would form a new, too small hole
138+
return None;
139+
} else {
140+
// the hole is bigger than necessary, so there is some padding behind the allocation
141+
Some(HoleInfo {
142+
addr: aligned_hole.addr + required_size,
143+
size: aligned_hole.size - required_size,
144+
})
138145
};
139146

140-
Some(HoleResult {
141-
hole: HoleInfo {
147+
Some(Allocation {
148+
info: HoleInfo {
142149
addr: aligned_hole.addr,
143150
size: required_size,
144151
},
@@ -147,20 +154,18 @@ fn split_hole(hole: HoleInfo, required_size: usize, required_align: usize) -> Op
147154
})
148155
}
149156

150-
fn allocate_first_fit(previous: &mut Hole, size: usize, align: usize) -> Option<HoleResult> {
151-
157+
fn allocate_first_fit(previous: &mut Hole, size: usize, align: usize) -> Option<Allocation> {
152158
previous.next
153159
.as_mut()
154160
.and_then(|current| split_hole(unsafe { current.get() }.info(), size, align))
155-
.map(|result| {
156-
previous.next = unsafe { previous.next.as_mut().unwrap().get_mut().next.take() };
157-
result
161+
.map(|allocation| {
162+
// hole is big enough, so remove it from the list by updating the previous pointer
163+
previous.next = previous.next_unwrap().next.take();
164+
allocation
158165
})
159166
.or_else(|| {
160167
// hole is too small, try next hole
161-
allocate_first_fit(unsafe { previous.next.as_mut().unwrap().get_mut() },
162-
size,
163-
align)
168+
allocate_first_fit(previous.next_unwrap(), size, align)
164169
})
165170
}
166171

0 commit comments

Comments
 (0)