Skip to main content

DepotAllocator

Struct DepotAllocator 

Source
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>

Source

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?
examples/basic.rs (line 163)
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>

Source

pub fn flush(&self)

Return the current bounded snapshot of every cache tier to the backend. No cache lock is held while invoking the backend. Concurrent frees may repopulate a tier after its snapshot is taken.

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>

Source§

fn allocate_physical( &self, ps: PageSize, count: NonZeroUsize, ) -> Result<usize, AllocError>

Allocate count contiguous frames of size ps. Read more
Source§

unsafe fn deallocate_physical( &self, ps: PageSize, count: NonZeroUsize, phys: usize, )

Return count contiguous frames of size ps starting at phys. Read more
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>

Source§

unsafe fn try_init( &self, phys_base: usize, span_len: usize, usable: &[PhysRange], ) -> Result<(), InitError>

Configure metadata over [phys_base, phys_base + span_len) and mark only the usable ranges free. Holes stay reserved. Read more
Source§

unsafe fn add_usable(&self, base: usize, len: usize)

Transition a reserved (never-freed) in-span range to free. Repeatable after try_init. base/len must satisfy the same per-range constraints as a usable entry. Read more
Source§

unsafe fn init(&self, phys_base: usize, span_len: usize, usable: &[PhysRange])

As try_init but panic on error. Read more
Source§

unsafe fn try_init_region( &self, phys_base: usize, len: usize, ) -> Result<(), InitError>

Convenience: initialise from a single fully-usable contiguous region [phys_base, phys_base + len). Read more
Source§

unsafe fn init_region(&self, phys_base: usize, len: usize)

As try_init_region but panic on error. Read more
Source§

impl<A: Send, S, const SLOTS: usize, const CAP: usize, const DEPOT_CAP: usize, I: InterruptControl> Send for DepotAllocator<A, S, SLOTS, CAP, DEPOT_CAP, I>

Source§

impl<A: Sync, S, const SLOTS: usize, const CAP: usize, const DEPOT_CAP: usize, I: InterruptControl> Sync for DepotAllocator<A, S, SLOTS, CAP, DEPOT_CAP, I>

Auto Trait Implementations§

§

impl<A, S, const SLOTS: usize, const CAP: usize = 128, const DEPOT_CAP: usize = 512, I = NoInterruptControl> !Freeze for DepotAllocator<A, S, SLOTS, CAP, DEPOT_CAP, I>

§

impl<A, S, const SLOTS: usize, const CAP: usize = 128, const DEPOT_CAP: usize = 512, I = NoInterruptControl> !RefUnwindSafe for DepotAllocator<A, S, SLOTS, CAP, DEPOT_CAP, I>

§

impl<A, S, const SLOTS: usize, const CAP: usize, const DEPOT_CAP: usize, I> Unpin for DepotAllocator<A, S, SLOTS, CAP, DEPOT_CAP, I>
where A: Unpin, <I as InterruptControl>::State: Unpin,

§

impl<A, S, const SLOTS: usize, const CAP: usize, const DEPOT_CAP: usize, I> UnsafeUnpin for DepotAllocator<A, S, SLOTS, CAP, DEPOT_CAP, I>

§

impl<A, S, const SLOTS: usize, const CAP: usize, const DEPOT_CAP: usize, I> UnwindSafe for DepotAllocator<A, S, SLOTS, CAP, DEPOT_CAP, I>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.