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
26pub mod global;
27#[doc(hidden)]
28pub use global::__reset_global_allocator_singleton_for_tests;
29pub use global::GlobalAllocator;
30
31/// External interface items supplied by the platform / allocator integrator.
32pub mod eii {
33    /// Translate a virtual address to a physical address.
34    #[eii(virt_to_phys_impl)]
35    pub fn virt_to_phys(vaddr: usize) -> usize;
36
37    /// Return the system-global slab pool.
38    #[eii(slab_pool_impl)]
39    pub fn slab_pool() -> &'static dyn crate::SlabPoolTrait;
40}
41
42// ---------------------------------------------------------------------------
43// Utility helpers (crate-internal)
44// ---------------------------------------------------------------------------
45
46#[inline]
47pub(crate) const fn align_up(pos: usize, align: usize) -> usize {
48    (pos + align - 1) & !(align - 1)
49}
50
51#[inline]
52pub(crate) const fn is_aligned(addr: usize, align: usize) -> bool {
53    addr & (align - 1) == 0
54}
55
56#[cfg(test)]
57mod test_eii_impls {
58    use core::{alloc::Layout, ptr::NonNull};
59
60    use super::eii::{slab_pool_impl, virt_to_phys_impl};
61    use super::{AllocError, AllocResult, SizeClass, SlabAllocResult, SlabPoolTrait, SlabTrait};
62
63    struct NullSlabPool;
64    struct NullSlab;
65
66    impl SlabTrait for NullSlab {
67        fn cpu_id(&self) -> usize {
68            0
69        }
70
71        fn page_size(&self) -> usize {
72            0x1000
73        }
74
75        fn alloc(&self, _layout: Layout) -> AllocResult<SlabAllocResult> {
76            Err(AllocError::NotInitialized)
77        }
78
79        fn add_slab(&self, _size_class: SizeClass, _base: usize, _bytes: usize) {}
80
81        fn dealloc_local(&self, _ptr: NonNull<u8>, _layout: Layout) -> super::SlabDeallocResult {
82            super::SlabDeallocResult::Done
83        }
84    }
85
86    static NULL_SLAB: NullSlab = NullSlab;
87
88    impl SlabPoolTrait for NullSlabPool {
89        fn current_slab(&self) -> &dyn SlabTrait {
90            &NULL_SLAB
91        }
92
93        fn owner_slab(&self, _cpu_idx: usize) -> &dyn SlabTrait {
94            &NULL_SLAB
95        }
96    }
97
98    static NULL_SLAB_POOL: NullSlabPool = NullSlabPool;
99
100    #[virt_to_phys_impl]
101    fn test_virt_to_phys(vaddr: usize) -> usize {
102        vaddr
103    }
104
105    #[slab_pool_impl]
106    fn test_slab_pool() -> &'static dyn SlabPoolTrait {
107        &NULL_SLAB_POOL
108    }
109}