buddy_system_allocator/
frame.rs1use super::prev_power_of_two;
2use alloc::collections::BTreeSet;
3use core::alloc::Layout;
4use core::cmp::{max, min};
5use core::ops::Range;
6
7#[cfg(feature = "use_spin")]
8use core::ops::Deref;
9#[cfg(feature = "use_spin")]
10use spin::Mutex;
11
12pub struct FrameAllocator<const ORDER: usize = 33> {
34 free_list: [BTreeSet<usize>; ORDER],
36
37 allocated: usize,
39 total: usize,
40}
41
42impl<const ORDER: usize> FrameAllocator<ORDER> {
43 pub const fn new() -> Self {
45 Self {
46 free_list: [const { BTreeSet::new() }; ORDER],
47 allocated: 0,
48 total: 0,
49 }
50 }
51
52 pub fn add_frame(&mut self, start: usize, end: usize) {
54 assert!(start <= end);
55
56 let mut total = 0;
57 let mut current_start = start;
58 let max_block_size = 1 << (ORDER - 1);
59
60 while current_start < end {
61 let lowbit = if current_start > 0 {
62 current_start & (!current_start + 1)
63 } else {
64 max_block_size
65 };
66 let size = min(
67 min(lowbit, prev_power_of_two(end - current_start)),
68 max_block_size,
69 );
70 total += size;
71
72 self.free_list[size.trailing_zeros() as usize].insert(current_start);
73 current_start += size;
74 }
75
76 self.total += total;
77 }
78
79 pub fn insert(&mut self, range: Range<usize>) {
81 self.add_frame(range.start, range.end);
82 }
83
84 pub fn alloc(&mut self, count: usize) -> Option<usize> {
87 let size = count.next_power_of_two();
88 self.alloc_power_of_two(size)
89 }
90
91 pub fn alloc_aligned(&mut self, layout: Layout) -> Option<usize> {
96 let size = max(layout.size().next_power_of_two(), layout.align());
97 self.alloc_power_of_two(size)
98 }
99
100 pub fn alloc_at(&mut self, start: usize, count: usize) -> Option<usize> {
108 let size = count.next_power_of_two();
109 self.alloc_at_power_of_two(start, size)
110 }
111
112 fn alloc_power_of_two(&mut self, size: usize) -> Option<usize> {
115 let class = size.trailing_zeros() as usize;
116 for i in class..self.free_list.len() {
117 if !self.free_list[i].is_empty() {
119 for j in (class + 1..i + 1).rev() {
121 if let Some(block_ref) = self.free_list[j].iter().next() {
122 let block = *block_ref;
123 self.free_list[j - 1].insert(block + (1 << (j - 1)));
124 self.free_list[j - 1].insert(block);
125 self.free_list[j].remove(&block);
126 } else {
127 return None;
128 }
129 }
130
131 let result = self.free_list[class].iter().next();
132 if let Some(result_ref) = result {
133 let result = *result_ref;
134 self.free_list[class].remove(&result);
135 self.allocated += size;
136 return Some(result);
137 } else {
138 return None;
139 }
140 }
141 }
142 None
143 }
144
145 fn alloc_at_power_of_two(&mut self, start: usize, size: usize) -> Option<usize> {
148 let class = size.trailing_zeros() as usize;
149
150 if start & (size - 1) != 0 {
151 return None;
152 }
153
154 for i in class..self.free_list.len() {
155 let block_start = start & !((1 << i) - 1);
156 if self.free_list[i].remove(&block_start) {
157 let mut current_start = block_start;
158 for j in (class..i).rev() {
159 let mid = current_start + (1 << j);
160 if start >= mid {
161 self.free_list[j].insert(current_start);
162 current_start = mid;
163 } else {
164 self.free_list[j].insert(mid);
165 }
166 }
167 self.allocated += size;
168 return Some(start);
169 }
170 }
171
172 None
173 }
174
175 pub fn dealloc(&mut self, start_frame: usize, count: usize) {
179 let size = count.next_power_of_two();
180 self.dealloc_power_of_two(start_frame, size)
181 }
182
183 pub fn dealloc_aligned(&mut self, start_frame: usize, layout: Layout) {
187 let size = max(layout.size().next_power_of_two(), layout.align());
188 self.dealloc_power_of_two(start_frame, size)
189 }
190
191 fn dealloc_power_of_two(&mut self, start_frame: usize, size: usize) {
194 let class = size.trailing_zeros() as usize;
195
196 let mut current_ptr = start_frame;
198 let mut current_class = class;
199 while current_class < self.free_list.len() - 1 {
200 let buddy = current_ptr ^ (1 << current_class);
201 if self.free_list[current_class].remove(&buddy) {
202 current_ptr = min(current_ptr, buddy);
204 current_class += 1;
205 } else {
206 break;
207 }
208 }
209
210 self.free_list[current_class].insert(current_ptr);
211 self.allocated -= size;
212 }
213}
214
215impl<const ORDER: usize> Default for FrameAllocator<ORDER> {
216 fn default() -> Self {
217 Self::new()
218 }
219}
220
221#[cfg(feature = "use_spin")]
239#[derive(Default)]
240pub struct LockedFrameAllocator<const ORDER: usize = 33>(Mutex<FrameAllocator<ORDER>>);
241
242#[cfg(feature = "use_spin")]
243impl<const ORDER: usize> LockedFrameAllocator<ORDER> {
244 pub const fn new() -> Self {
246 Self(Mutex::new(FrameAllocator::new()))
247 }
248}
249
250#[cfg(feature = "use_spin")]
251impl<const ORDER: usize> Deref for LockedFrameAllocator<ORDER> {
252 type Target = Mutex<FrameAllocator<ORDER>>;
253
254 fn deref(&self) -> &Mutex<FrameAllocator<ORDER>> {
255 &self.0
256 }
257}