pub struct DepotAllocator<A, S, const SLOTS: usize, const CAP: usize = 128, const DEPOT_CAP: usize = 512, I: InterruptControl = NoInterruptControl> { /* private fields */ }Expand description
A per-CPU magazine cache with a shared depot tier, over a backing physical
allocator. This extends MagazineAllocator with a second,
shared cache tier between the per-CPU magazines and the backend.
SLOTS is the number of per-CPU magazines, CAP each magazine’s depth, and
DEPOT_CAP the shared depot’s capacity in frames. CpuId::current_cpu is taken
modulo SLOTS. CAP defaults to 128, DEPOT_CAP to 512.
I is the InterruptControl strategy for the magazine and depot locks; it
defaults to NoInterruptControl.
Multi-frame requests first use the backend unchanged. On backend OOM, the
wrapper progressively returns cached frames and retries, preserving cache
contents once the request becomes satisfiable.
Implementations§
Source§impl<A, S, const SLOTS: usize, const CAP: usize, const DEPOT_CAP: usize, I: InterruptControl> DepotAllocator<A, S, SLOTS, CAP, DEPOT_CAP, I>
impl<A, S, const SLOTS: usize, const CAP: usize, const DEPOT_CAP: usize, I: InterruptControl> DepotAllocator<A, S, SLOTS, CAP, DEPOT_CAP, I>
Sourcepub const fn new(base_frame: PageSize, backend: A) -> Self
pub const fn new(base_frame: PageSize, backend: A) -> Self
Create a depot cache over backend. Call
init_region before use.
base_frame must match the backend’s base frame size.
Examples found in repository?
150fn compose_with_depot() {
151 /// Uniprocessor selector: every CPU maps to slot 0. A real kernel returns an
152 /// APIC id / `TPIDR_EL1` here.
153 struct OneCpu;
154 impl CpuId for OneCpu {
155 fn current_cpu() -> usize {
156 0
157 }
158 }
159 const SLOTS: usize = 8; // magazines (>= CPUs you want disjoint)
160
161 // Same const-new composability: the whole stack is one `static`-able value.
162 let mag: DepotAllocator<SummaryBuddyAllocator<ORDERS, IdentityProv>, OneCpu, SLOTS> =
163 DepotAllocator::new(BASE, SummaryBuddyAllocator::new(BASE));
164
165 let pool = Region::new(SPAN_FRAMES * BASE.bytes(), MAX_BLOCK);
166 // SAFETY: as above; here the whole region is usable, so the single-range
167 // convenience applies.
168 unsafe { mag.init_region(pool.addr(), SPAN_FRAMES * BASE.bytes()) };
169
170 println!("\n── DepotAllocator<SummaryBuddyAllocator> ──");
171 let a = mag.allocate_physical(BASE, n(1)).expect("mag alloc");
172 // SAFETY: `a` came from this allocator; freed once, then not reused by us.
173 unsafe { mag.deallocate_physical(BASE, n(1), a) };
174 let b = mag.allocate_physical(BASE, n(1)).expect("mag re-alloc");
175 println!("alloc {a:#x} -> free -> alloc {b:#x}");
176 assert_eq!(a, b, "the magazine should return the just-freed frame");
177 println!("re-alloc returned the cached frame (no backend round-trip).");
178 // SAFETY: final free of a live frame.
179 unsafe { mag.deallocate_physical(BASE, n(1), b) };
180}Source§impl<A: PhysicalAllocator, S: CpuId, const SLOTS: usize, const CAP: usize, const DEPOT_CAP: usize, I: InterruptControl> DepotAllocator<A, S, SLOTS, CAP, DEPOT_CAP, I>
impl<A: PhysicalAllocator, S: CpuId, const SLOTS: usize, const CAP: usize, const DEPOT_CAP: usize, I: InterruptControl> DepotAllocator<A, S, SLOTS, CAP, DEPOT_CAP, I>
Trait Implementations§
Source§impl<A: PhysicalAllocator, S: CpuId, const SLOTS: usize, const CAP: usize, const DEPOT_CAP: usize, I: InterruptControl> PhysicalAllocator for DepotAllocator<A, S, SLOTS, CAP, DEPOT_CAP, I>
impl<A: PhysicalAllocator, S: CpuId, const SLOTS: usize, const CAP: usize, const DEPOT_CAP: usize, I: InterruptControl> PhysicalAllocator for DepotAllocator<A, S, SLOTS, CAP, DEPOT_CAP, I>
Source§fn allocate_physical(
&self,
ps: PageSize,
count: NonZeroUsize,
) -> Result<usize, AllocError>
fn allocate_physical( &self, ps: PageSize, count: NonZeroUsize, ) -> Result<usize, AllocError>
Source§unsafe fn deallocate_physical(
&self,
ps: PageSize,
count: NonZeroUsize,
phys: usize,
)
unsafe fn deallocate_physical( &self, ps: PageSize, count: NonZeroUsize, phys: usize, )
Source§impl<A: RegionInit, S, const SLOTS: usize, const CAP: usize, const DEPOT_CAP: usize, I: InterruptControl> RegionInit for DepotAllocator<A, S, SLOTS, CAP, DEPOT_CAP, I>
impl<A: RegionInit, S, const SLOTS: usize, const CAP: usize, const DEPOT_CAP: usize, I: InterruptControl> RegionInit for DepotAllocator<A, S, SLOTS, CAP, DEPOT_CAP, I>
Source§unsafe fn try_init(
&self,
phys_base: usize,
span_len: usize,
usable: &[PhysRange],
) -> Result<(), InitError>
unsafe fn try_init( &self, phys_base: usize, span_len: usize, usable: &[PhysRange], ) -> Result<(), InitError>
[phys_base, phys_base + span_len) and mark only
the usable ranges free. Holes stay reserved. Read moreSource§unsafe fn add_usable(&self, base: usize, len: usize)
unsafe fn add_usable(&self, base: usize, len: usize)
Source§unsafe fn try_init_region(
&self,
phys_base: usize,
len: usize,
) -> Result<(), InitError>
unsafe fn try_init_region( &self, phys_base: usize, len: usize, ) -> Result<(), InitError>
[phys_base, phys_base + len). Read moreSource§unsafe fn init_region(&self, phys_base: usize, len: usize)
unsafe fn init_region(&self, phys_base: usize, len: usize)
try_init_region but panic on error. Read more