Skip to main content

osiris/mem/
alloc.rs

1//! This module provides a simple allocator.
2//! One implementation is the BestFitAllocator, which uses the best fit strategy.
3
4use core::ptr::NonNull;
5
6use crate::hal::mem::PhysAddr;
7
8use crate::error::Result;
9
10pub mod bestfit;
11
12/// Snapshot of allocator resource usage. Available when the `metrics` feature is enabled.
13#[cfg(any(feature = "metrics", metrics))]
14#[derive(Debug, Clone, Copy, Default)]
15pub struct Metrics {
16    pub total_bytes: usize,
17    pub free_bytes: usize,
18    pub free_blocks: usize,
19    pub alloc_count: u64,
20    pub free_count: u64,
21}
22
23#[cfg(any(feature = "metrics", metrics))]
24impl Metrics {
25    pub const fn new() -> Self {
26        Self {
27            total_bytes: 0,
28            free_bytes: 0,
29            free_blocks: 0,
30            alloc_count: 0,
31            free_count: 0,
32        }
33    }
34
35    pub fn allocated_bytes(&self) -> usize {
36        self.total_bytes.saturating_sub(self.free_bytes)
37    }
38
39    pub(crate) fn record_add_range(&mut self, total: usize, free: usize) {
40        self.total_bytes = self.total_bytes.saturating_add(total);
41        self.free_bytes = self.free_bytes.saturating_add(free);
42        self.free_blocks += 1;
43    }
44
45    pub(crate) fn record_alloc(&mut self, consumed_bytes: usize, blocks_removed: usize) {
46        self.free_bytes = self.free_bytes.saturating_sub(consumed_bytes);
47        self.free_blocks = self.free_blocks.saturating_sub(blocks_removed);
48        self.alloc_count += 1;
49    }
50
51    pub(crate) fn record_free(&mut self, added_bytes: usize) {
52        self.free_bytes = self.free_bytes.saturating_add(added_bytes);
53        self.free_blocks += 1;
54        self.free_count += 1;
55    }
56}
57
58#[cfg(target_pointer_width = "64")]
59pub const MAX_ADDR: usize = 2_usize.pow(48);
60
61#[cfg(target_pointer_width = "32")]
62pub const MAX_ADDR: usize = usize::MAX;
63
64/// Allocator trait that provides a way to allocate and free memory.
65/// Normally you don't need to use this directly, rather use the `boxed::Box` type.
66///
67/// # Safety
68///
69/// Every block returned by `malloc` must be freed by `free` exactly once.
70/// A pointer allocated by one allocator must not be freed by another allocator.
71/// Each range added to the allocator must be valid for the whole lifetime of the allocator and must not overlap with any other range.
72/// The lifetime of any allocation is only valid as long as the allocator is valid. (A pointer must not be used after the allocator is dropped.)
73pub trait Allocator {
74    unsafe fn malloc<T>(
75        &mut self,
76        size: usize,
77        align: usize,
78        request: Option<PhysAddr>,
79    ) -> Result<NonNull<T>>;
80    unsafe fn free<T>(&mut self, ptr: NonNull<T>, size: usize);
81}