1use crate::writer::Error;
10use inspect_format::{
11 Block, BlockAccessorExt, BlockAccessorMutExt, BlockIndex, BlockType, Free, ReadBytes, Reserved,
12 WriteBytes, constants, utils,
13};
14use std::cmp::min;
15
16#[derive(Debug)]
18pub struct Heap<T> {
19 pub(crate) container: T,
20 current_size_bytes: usize,
21 free_head_per_order: [BlockIndex; constants::NUM_ORDERS as usize],
22 allocated_blocks: usize,
23 deallocated_blocks: usize,
24 failed_allocations: usize,
25 has_header: bool,
26}
27
28impl<T: ReadBytes + WriteBytes> Heap<T> {
29 pub fn new(container: T) -> Result<Self, Error> {
31 let mut heap = Self::empty(container)?;
32 heap.init_header()?;
33 Ok(heap)
34 }
35
36 pub fn empty(container: T) -> Result<Self, Error> {
38 let mut heap = Heap {
39 container,
40 current_size_bytes: 0,
41 free_head_per_order: [BlockIndex::EMPTY; constants::NUM_ORDERS as usize],
42 allocated_blocks: 0,
43 deallocated_blocks: 0,
44 failed_allocations: 0,
45 has_header: false,
46 };
47 heap.grow_heap(constants::PAGE_SIZE_BYTES)?;
48 Ok(heap)
49 }
50
51 #[inline]
52 fn init_header(&mut self) -> Result<(), Error> {
53 let header_index =
54 self.allocate_block(inspect_format::utils::order_to_size(constants::HEADER_ORDER))?;
55 let heap_current_size = self.current_size_bytes;
56 self.container
57 .block_at_unchecked_mut::<Reserved>(header_index)
58 .become_header(heap_current_size)?;
59 self.has_header = true;
60 Ok(())
61 }
62
63 pub fn current_size(&self) -> usize {
65 self.current_size_bytes
66 }
67
68 pub fn maximum_size(&self) -> usize {
70 self.container.len()
71 }
72
73 pub fn total_allocated_blocks(&self) -> usize {
75 self.allocated_blocks
76 }
77
78 pub fn total_deallocated_blocks(&self) -> usize {
80 self.deallocated_blocks
81 }
82
83 pub fn failed_allocations(&self) -> usize {
85 self.failed_allocations
86 }
87
88 pub fn allocate_block(&mut self, min_size: usize) -> Result<BlockIndex, Error> {
90 let min_fit_order = utils::fit_order(min_size);
91 if min_fit_order >= constants::NUM_ORDERS as usize {
92 return Err(Error::InvalidBlockOrder(min_fit_order));
93 }
94 let min_fit_order = min_fit_order as u8;
95 let order_found = (min_fit_order..constants::NUM_ORDERS)
97 .find(|&i| self.is_free_block(self.free_head_per_order[i as usize], i).is_some());
98 let next_order = match order_found {
99 Some(order) => order,
100 None => {
101 self.grow_heap(self.current_size_bytes + constants::PAGE_SIZE_BYTES)?;
102 constants::NUM_ORDERS - 1
103 }
104 };
105 let block_index = self.free_head_per_order[next_order as usize];
106 while self.container.block_at(block_index).order() > min_fit_order {
107 self.split_block(block_index)?;
108 }
109 self.remove_free(block_index);
110 let _ = self.container.block_at_unchecked_mut::<Free>(block_index).become_reserved();
111 self.allocated_blocks += 1;
112 Ok(block_index)
113 }
114
115 pub fn free_block(&mut self, mut block_index: BlockIndex) -> Result<(), Error> {
117 let block = self.container.block_at(block_index);
118 if block.block_type() == Some(BlockType::Free) {
119 return Err(Error::BlockAlreadyFree(block_index));
120 }
121 let mut buddy_index = buddy(block_index, block.order());
122
123 while self.possible_to_merge(buddy_index, block_index) {
124 self.remove_free(buddy_index);
125 if buddy_index < block_index {
126 std::mem::swap(&mut buddy_index, &mut block_index);
127 }
128 let mut block = self.container.block_at_mut(block_index);
129 let order = block.order();
130 block.set_order(order + 1)?;
131 buddy_index = buddy(block_index, order + 1);
132 }
133 let block = self.container.block_at_unchecked_mut::<Reserved>(block_index);
134 let order = block.order();
135 let _ = block.become_free(self.free_head_per_order[order as usize]);
136 self.free_head_per_order[order as usize] = block_index;
137 self.deallocated_blocks += 1;
138 Ok(())
139 }
140
141 #[inline]
142 fn possible_to_merge(&self, buddy_index: BlockIndex, block_index: BlockIndex) -> bool {
143 let max_block_index = self.current_size_bytes / constants::MIN_ORDER_SIZE;
144 if *buddy_index as usize >= max_block_index {
145 return false;
146 }
147 self.container
148 .maybe_block_at::<Free>(buddy_index)
149 .map(|buddy_block| {
150 let block = self.container.block_at(block_index);
151 block.order() < constants::NUM_ORDERS - 1 && block.order() == buddy_block.order()
152 })
153 .unwrap_or(false)
154 }
155
156 pub(crate) fn bytes(&self) -> Vec<u8> {
158 self.container.get_slice(self.current_size_bytes).unwrap().to_vec()
159 }
160
161 #[inline]
162 fn grow_heap(&mut self, requested_size: usize) -> Result<(), Error> {
163 let container_size = self.container.len();
164 if requested_size > container_size || requested_size > constants::MAX_VMO_SIZE {
165 self.failed_allocations += 1;
166 return Err(Error::HeapMaxSizeReached);
167 }
168 let new_size = min(container_size, requested_size);
169 let min_index = BlockIndex::from_offset(self.current_size_bytes);
170 let mut last_index = self.free_head_per_order[(constants::NUM_ORDERS - 1) as usize];
171 let mut curr_index =
172 BlockIndex::from_offset(new_size - new_size % constants::PAGE_SIZE_BYTES);
173 loop {
174 curr_index -= BlockIndex::from_offset(constants::MAX_ORDER_SIZE);
175 Block::free(&mut self.container, curr_index, constants::NUM_ORDERS - 1, last_index)
176 .expect("Failed to create free block");
177 last_index = curr_index;
178 if curr_index <= min_index {
179 break;
180 }
181 }
182 self.free_head_per_order[(constants::NUM_ORDERS - 1) as usize] = last_index;
183 self.current_size_bytes = new_size;
184 if self.has_header {
185 self.container
186 .block_at_unchecked_mut(BlockIndex::HEADER)
187 .set_vmo_size(self.current_size_bytes as u32)?;
189 }
190 Ok(())
191 }
192
193 #[inline]
194 fn is_free_block(
195 &mut self,
196 index: BlockIndex,
197 expected_order: u8,
198 ) -> Option<Block<&mut T, Free>> {
199 if (*index as usize) >= self.current_size_bytes / constants::MIN_ORDER_SIZE {
201 return None;
202 }
203 self.container
204 .maybe_block_at_mut::<Free>(index)
205 .filter(|block| block.order() == expected_order)
206 }
207
208 #[inline]
209 fn remove_free(&mut self, block_index: BlockIndex) {
210 let block = self.container.block_at_unchecked::<Free>(block_index);
211 let free_next_index = block.free_next_index();
212 let order = block.order();
213 if order >= constants::NUM_ORDERS {
214 return;
215 }
216 let mut next_index = self.free_head_per_order[order as usize];
217 if next_index == block_index {
218 self.free_head_per_order[order as usize] = free_next_index;
219 return;
220 }
221 while let Some(mut curr_block) = self.is_free_block(next_index, order) {
222 next_index = curr_block.free_next_index();
223 if next_index == block_index {
224 curr_block.set_free_next_index(free_next_index);
225 return;
226 }
227 }
228 }
229
230 #[inline]
231 fn split_block(&mut self, block_index: BlockIndex) -> Result<(), Error> {
232 let block_order = self.container.block_at(block_index).order();
233 if block_order >= constants::NUM_ORDERS {
234 return Err(Error::InvalidBlockOrderAtIndex(block_order, block_index));
235 }
236 self.remove_free(block_index);
237 let buddy_index = buddy(block_index, block_order - 1);
238 let mut block = self.container.block_at_mut(block_index);
239 block.set_order(block_order - 1)?;
240 block.become_free(buddy_index);
241
242 let mut buddy = self.container.block_at_mut(buddy_index);
243 let buddy_order = block_order - 1;
244 buddy.set_order(buddy_order)?;
245 buddy.become_free(self.free_head_per_order[buddy_order as usize]);
246 self.free_head_per_order[buddy_order as usize] = block_index;
247 Ok(())
248 }
249}
250
251fn buddy(index: BlockIndex, order: u8) -> BlockIndex {
252 index ^ BlockIndex::from_offset(utils::order_to_size(order))
253}
254
255#[cfg(test)]
256mod tests {
257 use super::*;
258 use crate::reader::snapshot::{BackingBuffer, BlockIterator};
259 use inspect_format::{BlockType, Container, Header, block_testing};
260
261 #[derive(Debug)]
262 struct BlockDebug {
263 index: BlockIndex,
264 order: u8,
265 block_type: BlockType,
266 }
267
268 fn validate<T: WriteBytes + ReadBytes>(expected: &[BlockDebug], heap: &Heap<T>) {
269 let buffer = BackingBuffer::Bytes(heap.bytes());
270 let actual: Vec<BlockDebug> = BlockIterator::from(&buffer)
271 .map(|block| BlockDebug {
272 order: block.order(),
273 index: block.index(),
274 block_type: block.block_type().unwrap(),
275 })
276 .collect();
277 assert_eq!(expected.len(), actual.len());
278 for (i, result) in actual.iter().enumerate() {
279 assert_eq!(result.block_type, expected[i].block_type);
280 assert_eq!(result.index, expected[i].index);
281 assert_eq!(result.order, expected[i].order);
282 }
283 }
284
285 #[fuchsia::test]
286 fn test_possible_to_merge_out_of_bounds() {
287 let (container, _storage) = Container::read_and_write(4096).unwrap();
288 let heap = Heap::empty(container).unwrap();
289 let oob_buddy = BlockIndex::from_offset(8192);
290 let block_idx = BlockIndex::from(0);
291 assert!(!heap.possible_to_merge(oob_buddy, block_idx));
292 }
293
294 #[fuchsia::test]
295 fn empty_heap() {
296 let (container, _storage) = Container::read_and_write(4096).unwrap();
297 let heap = Heap::empty(container).unwrap();
298 assert_eq!(heap.current_size_bytes, 4096);
299 assert_eq!(heap.free_head_per_order, [BlockIndex::EMPTY; 8]);
300
301 let expected = [
302 BlockDebug { index: 0.into(), order: 7, block_type: BlockType::Free },
303 BlockDebug { index: 128.into(), order: 7, block_type: BlockType::Free },
304 ];
305 validate(&expected, &heap);
306 assert_eq!(*heap.free_head_per_order[7], 0);
307 assert_eq!(*heap.container.block_at_unchecked::<Free>(0.into()).free_next_index(), 128);
308 assert_eq!(*heap.container.block_at_unchecked::<Free>(128.into()).free_next_index(), 0);
309 assert_eq!(heap.failed_allocations, 0);
310 }
311
312 #[fuchsia::test]
313 fn new_heap() {
314 let (container, _storage) = Container::read_and_write(4096).unwrap();
315 let heap = Heap::new(container).unwrap();
316 assert_eq!(heap.current_size_bytes, 4096);
317 assert_eq!(
318 heap.free_head_per_order,
319 [
320 BlockIndex::from(0),
321 BlockIndex::from(2),
322 BlockIndex::from(4),
323 BlockIndex::from(8),
324 BlockIndex::from(16),
325 BlockIndex::from(32),
326 BlockIndex::from(64),
327 BlockIndex::from(128)
328 ]
329 );
330
331 let expected = [
332 BlockDebug { index: 0.into(), order: 1, block_type: BlockType::Header },
333 BlockDebug { index: 2.into(), order: 1, block_type: BlockType::Free },
334 BlockDebug { index: 4.into(), order: 2, block_type: BlockType::Free },
335 BlockDebug { index: 8.into(), order: 3, block_type: BlockType::Free },
336 BlockDebug { index: 16.into(), order: 4, block_type: BlockType::Free },
337 BlockDebug { index: 32.into(), order: 5, block_type: BlockType::Free },
338 BlockDebug { index: 64.into(), order: 6, block_type: BlockType::Free },
339 BlockDebug { index: 128.into(), order: 7, block_type: BlockType::Free },
340 ];
341 validate(&expected, &heap);
342 assert_eq!(*heap.container.block_at_unchecked::<Free>(128.into()).free_next_index(), 0);
343 assert_eq!(heap.failed_allocations, 0);
344 }
345
346 #[fuchsia::test]
347 fn allocate_and_free() {
348 let (container, _storage) = Container::read_and_write(4096).unwrap();
349 let mut heap = Heap::empty(container).unwrap();
350
351 for i in 0..=5 {
353 let block = heap.allocate_block(constants::MIN_ORDER_SIZE).unwrap();
354 assert_eq!(*block, i);
355 }
356
357 assert!(heap.free_block(BlockIndex::from(2)).is_ok());
359 assert!(heap.free_block(BlockIndex::from(4)).is_ok());
360 assert!(heap.free_block(BlockIndex::from(0)).is_ok());
361
362 let b = heap.allocate_block(constants::MIN_ORDER_SIZE).unwrap();
365 assert_eq!(*b, 0);
366 let b = heap.allocate_block(constants::MIN_ORDER_SIZE).unwrap();
367 assert_eq!(*b, 4);
368 let b = heap.allocate_block(constants::MIN_ORDER_SIZE).unwrap();
369 assert_eq!(*b, 2);
370
371 assert!(heap.free_block(BlockIndex::from(4)).is_ok());
373 assert!(heap.free_block(BlockIndex::from(2)).is_ok());
374 assert!(heap.free_block(BlockIndex::from(3)).is_ok());
375 assert!(heap.free_block(BlockIndex::from(5)).is_ok());
376
377 let expected = [
378 BlockDebug { index: 0.into(), order: 0, block_type: BlockType::Reserved },
379 BlockDebug { index: 1.into(), order: 0, block_type: BlockType::Reserved },
380 BlockDebug { index: 2.into(), order: 1, block_type: BlockType::Free },
381 BlockDebug { index: 4.into(), order: 2, block_type: BlockType::Free },
382 BlockDebug { index: 8.into(), order: 3, block_type: BlockType::Free },
383 BlockDebug { index: 16.into(), order: 4, block_type: BlockType::Free },
384 BlockDebug { index: 32.into(), order: 5, block_type: BlockType::Free },
385 BlockDebug { index: 64.into(), order: 6, block_type: BlockType::Free },
386 BlockDebug { index: 128.into(), order: 7, block_type: BlockType::Free },
387 ];
388 validate(&expected, &heap);
389 assert!(heap.free_head_per_order.iter().enumerate().skip(2).all(|(i, &j)| (1 << i) == *j));
390 let buffer = BackingBuffer::from(heap.bytes());
391 assert!(
392 BlockIterator::from(&buffer).skip(2).all(|b| *b
393 .cast::<Free>()
394 .unwrap()
395 .free_next_index()
396 == 0)
397 );
398
399 assert!(heap.free_block(BlockIndex::from(0)).is_ok());
401 let b = heap.allocate_block(2048).unwrap();
402 assert_eq!(*b, 128);
403
404 assert!(heap.free_block(BlockIndex::from(1)).is_ok());
407 let b = heap.allocate_block(2048).unwrap();
408 assert_eq!(*b, 0);
409
410 let expected = [
411 BlockDebug { index: 0.into(), order: 7, block_type: BlockType::Reserved },
412 BlockDebug { index: 128.into(), order: 7, block_type: BlockType::Reserved },
413 ];
414 validate(&expected, &heap);
415
416 assert!(heap.free_block(BlockIndex::from(0)).is_ok());
419 let b = heap.allocate_block(1024).unwrap();
420 assert_eq!(*b, 0);
421 let b = heap.allocate_block(1024).unwrap();
422 assert_eq!(*b, 64);
423 assert!(heap.free_block(BlockIndex::from(0)).is_ok());
424 assert!(heap.free_block(BlockIndex::from(64)).is_ok());
425
426 let b = heap.allocate_block(2048).unwrap();
429 assert_eq!(*b, 0);
430 assert!(heap.free_block(BlockIndex::from(0)).is_ok());
431
432 let expected = [
433 BlockDebug { index: 0.into(), order: 7, block_type: BlockType::Free },
434 BlockDebug { index: 128.into(), order: 7, block_type: BlockType::Reserved },
435 ];
436 validate(&expected, &heap);
437 assert_eq!(*heap.free_head_per_order[7], 0);
438 assert_eq!(*heap.container.block_at_unchecked::<Free>(0.into()).free_next_index(), 0);
439
440 assert!(heap.free_block(BlockIndex::from(128)).is_ok());
441 let expected = [
442 BlockDebug { index: 0.into(), order: 7, block_type: BlockType::Free },
443 BlockDebug { index: 128.into(), order: 7, block_type: BlockType::Free },
444 ];
445 validate(&expected, &heap);
446 assert_eq!(*heap.free_head_per_order[7], 128);
447 assert_eq!(*heap.container.block_at_unchecked::<Free>(0.into()).free_next_index(), 0);
448 assert_eq!(*heap.container.block_at_unchecked::<Free>(128.into()).free_next_index(), 0);
449 assert_eq!(heap.failed_allocations, 0);
450 }
451
452 #[fuchsia::test]
453 fn allocation_counters_work() {
454 let (container, _storage) = Container::read_and_write(4096).unwrap();
455 let mut heap = Heap::empty(container).unwrap();
456
457 let block_count_to_allocate: usize = 50;
458 for _ in 0..block_count_to_allocate {
459 heap.allocate_block(constants::MIN_ORDER_SIZE).unwrap();
460 }
461
462 assert_eq!(heap.total_allocated_blocks(), block_count_to_allocate);
463
464 let block_count_to_free: usize = 5;
465 for i in 0..block_count_to_free {
466 heap.free_block(BlockIndex::from(i as u32)).unwrap();
467 }
468
469 assert_eq!(heap.total_allocated_blocks(), block_count_to_allocate);
470 assert_eq!(heap.total_deallocated_blocks(), block_count_to_free);
471
472 for i in block_count_to_free..block_count_to_allocate {
473 heap.free_block(BlockIndex::from(i as u32)).unwrap();
474 }
475
476 assert_eq!(heap.total_allocated_blocks(), block_count_to_allocate);
477 assert_eq!(heap.total_deallocated_blocks(), block_count_to_allocate);
478 }
479
480 #[fuchsia::test]
481 fn allocate_merge() {
482 let (container, _storage) = Container::read_and_write(4096).unwrap();
483 let mut heap = Heap::empty(container).unwrap();
484 for i in 0..=3 {
485 let block = heap.allocate_block(constants::MIN_ORDER_SIZE).unwrap();
486 assert_eq!(*block, i);
487 }
488
489 assert!(heap.free_block(BlockIndex::from(2)).is_ok());
490 assert!(heap.free_block(BlockIndex::from(0)).is_ok());
491 assert!(heap.free_block(BlockIndex::from(1)).is_ok());
492
493 let expected = [
494 BlockDebug { index: 0.into(), order: 1, block_type: BlockType::Free },
495 BlockDebug { index: 2.into(), order: 0, block_type: BlockType::Free },
496 BlockDebug { index: 3.into(), order: 0, block_type: BlockType::Reserved },
497 BlockDebug { index: 4.into(), order: 2, block_type: BlockType::Free },
498 BlockDebug { index: 8.into(), order: 3, block_type: BlockType::Free },
499 BlockDebug { index: 16.into(), order: 4, block_type: BlockType::Free },
500 BlockDebug { index: 32.into(), order: 5, block_type: BlockType::Free },
501 BlockDebug { index: 64.into(), order: 6, block_type: BlockType::Free },
502 BlockDebug { index: 128.into(), order: 7, block_type: BlockType::Free },
503 ];
504 validate(&expected, &heap);
505 assert!(heap.free_head_per_order.iter().enumerate().skip(3).all(|(i, &j)| (1 << i) == *j));
506 let buffer = BackingBuffer::from(heap.bytes());
507 assert!(
508 BlockIterator::from(&buffer).skip(3).all(|b| *b
509 .cast::<Free>()
510 .unwrap()
511 .free_next_index()
512 == 0)
513 );
514 assert_eq!(*heap.free_head_per_order[1], 0);
515 assert_eq!(*heap.free_head_per_order[0], 2);
516 assert_eq!(*heap.container.block_at_unchecked::<Free>(0.into()).free_next_index(), 0);
517 assert_eq!(*heap.container.block_at_unchecked::<Free>(2.into()).free_next_index(), 0);
518
519 assert!(heap.free_block(BlockIndex::from(3)).is_ok());
520 let expected = [
521 BlockDebug { index: 0.into(), order: 7, block_type: BlockType::Free },
522 BlockDebug { index: 128.into(), order: 7, block_type: BlockType::Free },
523 ];
524 validate(&expected, &heap);
525 assert_eq!(*heap.free_head_per_order[1], 0);
526 assert_eq!(*heap.container.block_at_unchecked::<Free>(0.into()).free_next_index(), 128);
527 assert_eq!(*heap.container.block_at_unchecked::<Free>(128.into()).free_next_index(), 0);
528 }
529
530 #[fuchsia::test]
531 fn extend() {
532 let (container, _storage) = Container::read_and_write(8 * 2048).unwrap();
533 let mut heap = Heap::empty(container).unwrap();
534
535 let b = heap.allocate_block(2048).unwrap();
536 assert_eq!(*b, 0);
537 let b = heap.allocate_block(2048).unwrap();
538 assert_eq!(*b, 128);
539 let b = heap.allocate_block(2048).unwrap();
540 assert_eq!(*b, 256);
541
542 let expected = [
543 BlockDebug { index: 0.into(), order: 7, block_type: BlockType::Reserved },
544 BlockDebug { index: 128.into(), order: 7, block_type: BlockType::Reserved },
545 BlockDebug { index: 256.into(), order: 7, block_type: BlockType::Reserved },
546 BlockDebug { index: 384.into(), order: 7, block_type: BlockType::Free },
547 ];
548 validate(&expected, &heap);
549 assert_eq!(*heap.free_head_per_order[7], 384);
550 assert_eq!(*heap.container.block_at_unchecked::<Free>(384.into()).free_next_index(), 0);
551
552 let b = heap.allocate_block(2048).unwrap();
553 assert_eq!(*b, 384);
554 let b = heap.allocate_block(2048).unwrap();
555 assert_eq!(*b, 512);
556
557 assert!(heap.free_block(BlockIndex::from(0)).is_ok());
558 assert!(heap.free_block(BlockIndex::from(128)).is_ok());
559 assert!(heap.free_block(BlockIndex::from(256)).is_ok());
560 assert!(heap.free_block(BlockIndex::from(384)).is_ok());
561 assert!(heap.free_block(BlockIndex::from(512)).is_ok());
562
563 let expected = [
564 BlockDebug { index: 0.into(), order: 7, block_type: BlockType::Free },
565 BlockDebug { index: 128.into(), order: 7, block_type: BlockType::Free },
566 BlockDebug { index: 256.into(), order: 7, block_type: BlockType::Free },
567 BlockDebug { index: 384.into(), order: 7, block_type: BlockType::Free },
568 BlockDebug { index: 512.into(), order: 7, block_type: BlockType::Free },
569 BlockDebug { index: 640.into(), order: 7, block_type: BlockType::Free },
570 ];
571 validate(&expected, &heap);
572 assert_eq!(heap.current_size_bytes, 2048 * 4 + 4096);
573 assert_eq!(*heap.free_head_per_order[7], 512);
574 assert_eq!(*heap.container.block_at_unchecked::<Free>(512.into()).free_next_index(), 384);
575 assert_eq!(*heap.container.block_at_unchecked::<Free>(384.into()).free_next_index(), 256);
576 assert_eq!(*heap.container.block_at_unchecked::<Free>(256.into()).free_next_index(), 128);
577 assert_eq!(*heap.container.block_at_unchecked::<Free>(128.into()).free_next_index(), 0);
578 assert_eq!(*heap.container.block_at_unchecked::<Free>(0.into()).free_next_index(), 640);
579 assert_eq!(*heap.container.block_at_unchecked::<Free>(640.into()).free_next_index(), 0);
580 assert_eq!(heap.failed_allocations, 0);
581 }
582
583 #[fuchsia::test]
584 fn extend_error() {
585 let (container, _storage) = Container::read_and_write(4 * 2048).unwrap();
586 let mut heap = Heap::empty(container).unwrap();
587
588 let b = heap.allocate_block(2048).unwrap();
589 assert_eq!(*b, 0);
590 let b = heap.allocate_block(2048).unwrap();
591 assert_eq!(*b, 128);
592 let b = heap.allocate_block(2048).unwrap();
593 assert_eq!(*b, 256);
594
595 let expected = [
596 BlockDebug { index: 0.into(), order: 7, block_type: BlockType::Reserved },
597 BlockDebug { index: 128.into(), order: 7, block_type: BlockType::Reserved },
598 BlockDebug { index: 256.into(), order: 7, block_type: BlockType::Reserved },
599 BlockDebug { index: 384.into(), order: 7, block_type: BlockType::Free },
600 ];
601 validate(&expected, &heap);
602
603 let b = heap.allocate_block(2048).unwrap();
604 assert_eq!(*b, 384);
605 assert_eq!(heap.failed_allocations, 0);
606 assert!(heap.allocate_block(2048).is_err());
607 assert_eq!(heap.failed_allocations, 1);
608 assert!(heap.allocate_block(2048).is_err());
609 assert_eq!(heap.failed_allocations, 2);
610
611 assert!(heap.free_block(BlockIndex::from(0)).is_ok());
612 assert!(heap.free_block(BlockIndex::from(128)).is_ok());
613 assert!(heap.free_block(BlockIndex::from(256)).is_ok());
614 assert!(heap.free_block(BlockIndex::from(384)).is_ok());
615
616 let expected = [
617 BlockDebug { index: 0.into(), order: 7, block_type: BlockType::Free },
618 BlockDebug { index: 128.into(), order: 7, block_type: BlockType::Free },
619 BlockDebug { index: 256.into(), order: 7, block_type: BlockType::Free },
620 BlockDebug { index: 384.into(), order: 7, block_type: BlockType::Free },
621 ];
622 validate(&expected, &heap);
623 }
624
625 #[fuchsia::test]
626 fn extend_vmo_greater_max_size() {
627 let (container, _storage) =
628 Container::read_and_write(constants::MAX_VMO_SIZE + 2048).unwrap();
629 let mut heap = Heap::empty(container).unwrap();
630
631 for n in 0_u32..(constants::MAX_VMO_SIZE / constants::MAX_ORDER_SIZE).try_into().unwrap() {
632 let b = heap.allocate_block(2048).unwrap();
633 assert_eq!(*b, n * 128);
634 }
635 assert_eq!(heap.failed_allocations, 0);
636 assert!(heap.allocate_block(2048).is_err());
637 assert_eq!(heap.failed_allocations, 1);
638
639 for n in 0_u32..(constants::MAX_VMO_SIZE / constants::MAX_ORDER_SIZE).try_into().unwrap() {
640 assert!(heap.free_block(BlockIndex::from(n * 128)).is_ok());
641 }
642 }
643
644 #[fuchsia::test]
645 fn dont_reinterpret_upper_block_contents() {
646 let (container, _storage) = Container::read_and_write(4096).unwrap();
647 let mut heap = Heap::empty(container).unwrap();
648
649 assert_eq!(*heap.allocate_block(constants::MIN_ORDER_SIZE).unwrap(), 0);
651 let b1 = heap.allocate_block(utils::order_to_size(1)).unwrap();
652 assert_eq!(*b1, 2);
653 assert_eq!(*heap.allocate_block(utils::order_to_size(1)).unwrap(), 4);
654
655 {
657 let mut block = heap.container.block_at_mut(3.into());
658 block_testing::override_header(&mut block, 0xffffffff);
659 block_testing::override_payload(&mut block, 0xffffffff);
660 }
661
662 assert!(heap.free_block(b1).is_ok());
664
665 assert_eq!(*heap.allocate_block(constants::MIN_ORDER_SIZE).unwrap(), 1);
667 assert_eq!(*heap.allocate_block(constants::MIN_ORDER_SIZE).unwrap(), 2);
668
669 assert_eq!(*heap.allocate_block(constants::MIN_ORDER_SIZE).unwrap(), 3);
671
672 let expected = [
673 BlockDebug { index: 0.into(), order: 0, block_type: BlockType::Reserved },
674 BlockDebug { index: 1.into(), order: 0, block_type: BlockType::Reserved },
675 BlockDebug { index: 2.into(), order: 0, block_type: BlockType::Reserved },
676 BlockDebug { index: 3.into(), order: 0, block_type: BlockType::Reserved },
677 BlockDebug { index: 4.into(), order: 1, block_type: BlockType::Reserved },
678 BlockDebug { index: 6.into(), order: 1, block_type: BlockType::Free },
679 BlockDebug { index: 8.into(), order: 3, block_type: BlockType::Free },
680 BlockDebug { index: 16.into(), order: 4, block_type: BlockType::Free },
681 BlockDebug { index: 32.into(), order: 5, block_type: BlockType::Free },
682 BlockDebug { index: 64.into(), order: 6, block_type: BlockType::Free },
683 BlockDebug { index: 128.into(), order: 7, block_type: BlockType::Free },
684 ];
685 validate(&expected, &heap);
686 }
687
688 #[fuchsia::test]
689 fn update_header_vmo_size() {
690 let (container, _storage) = Container::read_and_write(3 * 4096).unwrap();
691 let mut heap = Heap::new(container).unwrap();
692 assert_eq!(
693 heap.container
694 .block_at_unchecked::<Header>(BlockIndex::HEADER)
695 .vmo_size()
696 .unwrap()
697 .unwrap() as usize,
698 heap.current_size()
699 );
700 let b = heap.allocate_block(2048).unwrap();
701 assert_eq!(*b, 128);
702 assert_eq!(
703 heap.container
704 .block_at_unchecked::<Header>(BlockIndex::HEADER)
705 .vmo_size()
706 .unwrap()
707 .unwrap() as usize,
708 heap.current_size()
709 );
710 let b = heap.allocate_block(2048).unwrap();
711 assert_eq!(*b, 256);
712 assert_eq!(
713 heap.container
714 .block_at_unchecked::<Header>(BlockIndex::HEADER)
715 .vmo_size()
716 .unwrap()
717 .unwrap() as usize,
718 heap.current_size()
719 );
720 let b = heap.allocate_block(2048).unwrap();
721 assert_eq!(*b, 384);
722 assert_eq!(
723 heap.container
724 .block_at_unchecked::<Header>(BlockIndex::HEADER)
725 .vmo_size()
726 .unwrap()
727 .unwrap() as usize,
728 heap.current_size()
729 );
730
731 let expected = [
732 BlockDebug { index: 0.into(), order: 1, block_type: BlockType::Header },
733 BlockDebug { index: 2.into(), order: 1, block_type: BlockType::Free },
734 BlockDebug { index: 4.into(), order: 2, block_type: BlockType::Free },
735 BlockDebug { index: 8.into(), order: 3, block_type: BlockType::Free },
736 BlockDebug { index: 16.into(), order: 4, block_type: BlockType::Free },
737 BlockDebug { index: 32.into(), order: 5, block_type: BlockType::Free },
738 BlockDebug { index: 64.into(), order: 6, block_type: BlockType::Free },
739 BlockDebug { index: 128.into(), order: 7, block_type: BlockType::Reserved },
740 BlockDebug { index: 256.into(), order: 7, block_type: BlockType::Reserved },
741 BlockDebug { index: 384.into(), order: 7, block_type: BlockType::Reserved },
742 ];
743 validate(&expected, &heap);
744
745 let b = heap.allocate_block(2048).unwrap();
746 assert_eq!(*b, 512);
747 assert_eq!(
748 heap.container
749 .block_at_unchecked::<Header>(BlockIndex::HEADER)
750 .vmo_size()
751 .unwrap()
752 .unwrap() as usize,
753 heap.current_size()
754 );
755 let b = heap.allocate_block(2048).unwrap();
756 assert_eq!(*b, 640);
757 assert_eq!(
758 heap.container
759 .block_at_unchecked::<Header>(BlockIndex::HEADER)
760 .vmo_size()
761 .unwrap()
762 .unwrap() as usize,
763 heap.current_size()
764 );
765 assert_eq!(heap.failed_allocations, 0);
766 assert!(heap.allocate_block(2048).is_err());
767 assert_eq!(
768 heap.container
769 .block_at_unchecked::<Header>(BlockIndex::HEADER)
770 .vmo_size()
771 .unwrap()
772 .unwrap() as usize,
773 heap.current_size()
774 );
775 assert_eq!(heap.failed_allocations, 1);
776
777 assert!(heap.free_block(BlockIndex::from(128)).is_ok());
778 assert!(heap.free_block(BlockIndex::from(256)).is_ok());
779 assert!(heap.free_block(BlockIndex::from(384)).is_ok());
780 assert!(heap.free_block(BlockIndex::from(512)).is_ok());
781 assert!(heap.free_block(BlockIndex::from(640)).is_ok());
782 assert_eq!(
783 heap.container
784 .block_at_unchecked::<Header>(BlockIndex::HEADER)
785 .vmo_size()
786 .unwrap()
787 .unwrap() as usize,
788 heap.current_size()
789 );
790
791 assert!(heap.free_block(BlockIndex::HEADER).is_ok());
792
793 let expected = [
794 BlockDebug { index: 0.into(), order: 7, block_type: BlockType::Free },
795 BlockDebug { index: 128.into(), order: 7, block_type: BlockType::Free },
796 BlockDebug { index: 256.into(), order: 7, block_type: BlockType::Free },
797 BlockDebug { index: 384.into(), order: 7, block_type: BlockType::Free },
798 BlockDebug { index: 512.into(), order: 7, block_type: BlockType::Free },
799 BlockDebug { index: 640.into(), order: 7, block_type: BlockType::Free },
800 ];
801 validate(&expected, &heap);
802 }
803}