Thanks to visit codestin.com
Credit goes to docs.rs

Skip to main content

ax_allocator/
lib.rs

1//! Various allocator algorithms in a unified interface.
2//!
3//! There are three types of allocators:
4//!
5//! - [`ByteAllocator`]: Byte-granularity memory allocator. (e.g.,
6//!   [`BuddyByteAllocator`], [`SlabByteAllocator`])
7//! - [`PageAllocator`]: Page-granularity memory allocator. (e.g.,
8//!   [`BitmapPageAllocator`])
9//! - [`IdAllocator`]: Used to allocate unique IDs.
10
11#![no_std]
12#![cfg_attr(feature = "allocator_api", feature(allocator_api))]
13
14#[cfg(feature = "bitmap")]
15mod bitmap;
16#[cfg(feature = "bitmap")]
17pub use bitmap::BitmapPageAllocator;
18
19#[cfg(feature = "buddy")]
20mod buddy;
21#[cfg(feature = "buddy")]
22pub use buddy::BuddyByteAllocator;
23
24#[cfg(feature = "slab")]
25mod slab;
26#[cfg(feature = "slab")]
27pub use slab::SlabByteAllocator;
28
29#[cfg(feature = "tlsf")]
30mod tlsf;
31use core::{alloc::Layout, ptr::NonNull};
32
33#[cfg(feature = "ax-errno")]
34use ax_errno::AxError;
35#[cfg(feature = "tlsf")]
36pub use tlsf::TlsfByteAllocator;
37
38/// The error type used for allocation.
39#[derive(Debug)]
40pub enum AllocError {
41    /// Invalid `size` or alignment. (e.g. unaligned)
42    InvalidParam,
43    /// Memory added by `add_memory` overlapped with existed memory.
44    MemoryOverlap,
45    /// No enough memory to allocate.
46    NoMemory,
47    /// Deallocate an unallocated memory region.
48    NotAllocated,
49}
50
51#[cfg(feature = "ax-errno")]
52impl From<AllocError> for AxError {
53    fn from(value: AllocError) -> Self {
54        match value {
55            AllocError::NoMemory => AxError::NoMemory,
56            _ => AxError::InvalidInput,
57        }
58    }
59}
60
61/// A [`Result`] type with [`AllocError`] as the error type.
62pub type AllocResult<T = ()> = Result<T, AllocError>;
63
64/// The base allocator inherited by other allocators.
65pub trait BaseAllocator {
66    /// Initialize the allocator with a free memory region.
67    fn init(&mut self, start: usize, size: usize);
68
69    /// Add a free memory region to the allocator.
70    fn add_memory(&mut self, start: usize, size: usize) -> AllocResult;
71}
72
73/// Byte-granularity allocator.
74pub trait ByteAllocator: BaseAllocator {
75    /// Allocate memory with the given size (in bytes) and alignment.
76    fn alloc(&mut self, layout: Layout) -> AllocResult<NonNull<u8>>;
77
78    /// Deallocate memory at the given position, size, and alignment.
79    fn dealloc(&mut self, pos: NonNull<u8>, layout: Layout);
80
81    /// Returns total memory size in bytes.
82    fn total_bytes(&self) -> usize;
83
84    /// Returns allocated memory size in bytes.
85    fn used_bytes(&self) -> usize;
86
87    /// Returns available memory size in bytes.
88    fn available_bytes(&self) -> usize;
89}
90
91/// Page-granularity allocator.
92pub trait PageAllocator: BaseAllocator {
93    /// The size of a memory page.
94    const PAGE_SIZE: usize;
95
96    /// Allocate contiguous memory pages with given count and byte alignment.
97    ///
98    /// `align` is the requested alignment in bytes, not a log2/exponent.
99    fn alloc_pages(&mut self, num_pages: usize, align: usize) -> AllocResult<usize>;
100
101    /// Deallocate contiguous memory pages with given position and count.
102    fn dealloc_pages(&mut self, pos: usize, num_pages: usize);
103
104    /// Allocate contiguous memory pages with given base address, count and byte alignment.
105    ///
106    /// `align` is the requested alignment in bytes, not a log2/exponent.
107    fn alloc_pages_at(&mut self, base: usize, num_pages: usize, align: usize)
108    -> AllocResult<usize>;
109
110    /// Returns the total number of memory pages.
111    fn total_pages(&self) -> usize;
112
113    /// Returns the number of allocated memory pages.
114    fn used_pages(&self) -> usize;
115
116    /// Returns the number of available memory pages.
117    fn available_pages(&self) -> usize;
118}
119
120/// Used to allocate unique IDs (e.g., thread ID).
121pub trait IdAllocator: BaseAllocator {
122    /// Allocate contiguous IDs with given count and alignment.
123    fn alloc_id(&mut self, count: usize, align_pow2: usize) -> AllocResult<usize>;
124
125    /// Deallocate contiguous IDs with given position and count.
126    fn dealloc_id(&mut self, start_id: usize, count: usize);
127
128    /// Whether the given `id` was allocated.
129    fn is_allocated(&self, id: usize) -> bool;
130
131    /// Mark the given `id` has been allocated and cannot be reallocated.
132    fn alloc_fixed_id(&mut self, id: usize) -> AllocResult;
133
134    /// Returns the maximum number of supported IDs.
135    fn size(&self) -> usize;
136
137    /// Returns the number of allocated IDs.
138    fn used(&self) -> usize;
139
140    /// Returns the number of available IDs.
141    fn available(&self) -> usize;
142}
143
144#[inline]
145#[allow(dead_code)]
146const fn align_down(pos: usize, align: usize) -> usize {
147    pos & !(align - 1)
148}
149
150#[inline]
151#[allow(dead_code)]
152const fn align_up(pos: usize, align: usize) -> usize {
153    (pos + align - 1) & !(align - 1)
154}
155
156/// Checks whether the address has the demanded alignment.
157///
158/// Equivalent to `addr % align == 0`, but the alignment must be a power of two.
159#[inline]
160#[allow(dead_code)]
161const fn is_aligned(base_addr: usize, align: usize) -> bool {
162    base_addr & (align - 1) == 0
163}
164
165#[cfg(feature = "allocator_api")]
166mod allocator_api {
167    extern crate alloc;
168
169    use alloc::rc::Rc;
170    use core::{
171        alloc::{AllocError, Allocator, Layout},
172        cell::RefCell,
173        ptr::NonNull,
174    };
175
176    use super::ByteAllocator;
177
178    /// A byte-allocator wrapped in [`Rc<RefCell>`] that implements [`core::alloc::Allocator`].
179    pub struct AllocatorRc<A: ByteAllocator>(Rc<RefCell<A>>);
180
181    impl<A: ByteAllocator> AllocatorRc<A> {
182        /// Creates a new allocator with the given memory pool.
183        pub fn new(mut inner: A, pool: &mut [u8]) -> Self {
184            inner.init(pool.as_mut_ptr() as usize, pool.len());
185            Self(Rc::new(RefCell::new(inner)))
186        }
187    }
188
189    unsafe impl<A: ByteAllocator> Allocator for AllocatorRc<A> {
190        fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
191            match layout.size() {
192                0 => Ok(NonNull::slice_from_raw_parts(NonNull::dangling(), 0)),
193                size => {
194                    let raw_addr = self.0.borrow_mut().alloc(layout).map_err(|_| AllocError)?;
195                    Ok(NonNull::slice_from_raw_parts(raw_addr, size))
196                }
197            }
198        }
199
200        unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
201            self.0.borrow_mut().dealloc(ptr, layout)
202        }
203    }
204
205    impl<A: ByteAllocator> Clone for AllocatorRc<A> {
206        fn clone(&self) -> Self {
207            Self(self.0.clone())
208        }
209    }
210}
211
212#[cfg(feature = "allocator_api")]
213pub use allocator_api::AllocatorRc;