Skip to main content

buddy_slab_allocator/
lib.rs

1//! # buddy-slab-allocator
2//!
3//! A `#![no_std]` memory allocator featuring:
4//!
5//! - **Buddy page allocator** — page-metadata-based with intrusive free lists
6//! - **Slab allocator** — bitmap-based with lock-free cross-CPU freeing (Linux SLUB inspired)
7//! - **Global allocator** — composes buddy + per-CPU slab, implements [`core::alloc::GlobalAlloc`]
8//!
9//! Both buddy and slab allocators can be used standalone.
10
11#![no_std]
12#![feature(extern_item_impls)]
13
14mod error;
15pub use error::{AllocError, AllocResult};
16
17pub mod buddy;
18pub use buddy::{BuddyAllocator, ManagedSection};
19
20pub mod slab;
21pub use slab::{
22    PerCpuSlab, SizeClass, SlabAllocResult, SlabAllocator, SlabDeallocResult,
23    SlabPoolDeallocResult, SlabPoolTrait, SlabTrait, StaticSlabPool,
24};
25
26#[cfg(all(axtest, feature = "axtest"))]
27mod axtest;
28
29pub mod global;
30#[doc(hidden)]
31pub use global::__reset_global_allocator_singleton_for_tests;
32pub use global::GlobalAllocator;
33
34/// External interface items supplied by the platform / allocator integrator.
35pub mod eii {
36    /// Translate a virtual address to a physical address.
37    #[eii(virt_to_phys_impl)]
38    pub fn virt_to_phys(vaddr: usize) -> usize;
39
40    /// Return the system-global slab pool.
41    #[eii(slab_pool_impl)]
42    pub fn slab_pool() -> &'static dyn crate::SlabPoolTrait;
43}
44
45// ---------------------------------------------------------------------------
46// Utility helpers (crate-internal)
47// ---------------------------------------------------------------------------
48
49#[inline]
50pub(crate) const fn align_up(pos: usize, align: usize) -> usize {
51    (pos + align - 1) & !(align - 1)
52}
53
54#[inline]
55pub(crate) const fn is_aligned(addr: usize, align: usize) -> bool {
56    addr & (align - 1) == 0
57}
58
59#[cfg(test)]
60mod test_eii_impls {
61    use core::{alloc::Layout, ptr::NonNull};
62
63    use super::{
64        AllocError, AllocResult, SizeClass, SlabAllocResult, SlabPoolTrait, SlabTrait,
65        eii::{slab_pool_impl, virt_to_phys_impl},
66    };
67
68    struct NullSlabPool;
69    struct NullSlab;
70
71    impl SlabTrait for NullSlab {
72        fn cpu_id(&self) -> usize {
73            0
74        }
75
76        fn page_size(&self) -> usize {
77            0x1000
78        }
79
80        fn alloc(&self, _layout: Layout) -> AllocResult<SlabAllocResult> {
81            Err(AllocError::NotInitialized)
82        }
83
84        fn add_slab(&self, _size_class: SizeClass, _base: usize, _bytes: usize) {}
85
86        fn dealloc_local(&self, _ptr: NonNull<u8>, _layout: Layout) -> super::SlabDeallocResult {
87            super::SlabDeallocResult::Done
88        }
89    }
90
91    static NULL_SLAB: NullSlab = NullSlab;
92
93    impl SlabPoolTrait for NullSlabPool {
94        fn current_slab(&self) -> &dyn SlabTrait {
95            &NULL_SLAB
96        }
97
98        fn owner_slab(&self, _cpu_idx: usize) -> &dyn SlabTrait {
99            &NULL_SLAB
100        }
101    }
102
103    static NULL_SLAB_POOL: NullSlabPool = NullSlabPool;
104
105    #[virt_to_phys_impl]
106    fn test_virt_to_phys(vaddr: usize) -> usize {
107        vaddr
108    }
109
110    #[slab_pool_impl]
111    fn test_slab_pool() -> &'static dyn SlabPoolTrait {
112        &NULL_SLAB_POOL
113    }
114}