Expand description
§RegionAllocator
§Overview
A RegionAllocator is a utility class designed to help with the bookkeeping
involved in managing the allocation/partitioning of a 64-bit space into
non-overlapping “Regions”. In addition to the RegionAllocator, there are two
other classes involved in the use of a RegionAllocator;
Region and RegionPool.
A Region consists of an unsigned 64-bit base address and an unsigned 64-bit
size. A Region is considered valid iff its size is non-zero, and it does not
wrap its 64-bit space.
See the “Memory Allocation” section for a discussion of the RegionPool.
RegionAllocator users can create an allocator and then add any number of
non-overlapping Regions to its pool of regions available for allocation.
They may then request that regions be allocated from the pool either by
requesting that a region be allocated with a particular size/alignment, or
by asking for a specific base/size. The RegionAllocator will manage all of
the bookkeeping involved in breaking available regions into smaller chunks,
tracking allocated regions, and re-merging regions when they are returned to
the allocator.
§Memory Allocation
RegionAllocators require dynamically allocated memory in order to store the
bookkeeping required for managing available regions. In order to control
heap fragmentation and the frequency of heap interaction, a RegionPool object
may be used to allocate bookkeeping overhead in larger slabs which are carved up
and placed on a free list to be used by a RegionAllocator. RegionPools are
created with a defined slab size as well as a maximum memory limit. The pool
will initially allocate a single slab, but will attempt to grow any time
bookkeeping is needed but the free list is empty and the allocation of
another slab would not push the allocator over its maximum memory limit.
RegionPools are ref-counted objects (RefPtr<RegionPool>) that may be shared by multiple
RegionAllocators. This allows sub-systems which use multiple allocators to
impose system-wide limits on bookkeeping overhead. If a RegionPool allocator
is to be used, it must be assigned to the RegionAllocator before any regions
can be added or allocated, and the pool may not be re-assigned while the
allocator is using any bookkeeping from the pool.
§APIs and Object lifecycle management
The API makes use of fbl managed pointer types in order to simplify lifecycle
management. RegionPools are managed with RefPtr<RegionPool> while Regions are handed
out via UniquePtr<Region>. RegionAllocators themselves impose no lifecycle
restrictions and may be heap allocated, stack allocated, or embedded directly
in objects as the user sees fit. It is an error to allow a RegionAllocator
to destruct while there are allocations in flight.
§Thread Safety
RegionAllocator and RegionPools use KMutex or RawMutex objects to provide thread
safety in multi-threaded environments. As such, RegionAllocators are not
currently suitable for use in code which may run at IRQ context, or which
must never block.
Each RegionAllocator has its own mutex allowing for concurrent access across
multiple allocators, even when the allocators share the same RegionPool.
RegionPools also hold their own mutex which may be obtained by an Allocator
while holding the Allocator’s Mutex.
§Simple Usage Example
use pin_init::stack_pin_init;
use region_alloc::{RegionAllocator, RegionPool, RegionSpan, AllowOverlap};
use zx_status::Status;
// Create a pool and assign it to a stack allocated allocator. Limit the
// bookkeeping memory to 32KB. This will ensure that no heap interactions
// take place after startup (during operation).
let pool = RegionPool::create(32 << 10).map_err(|_| Status::NO_MEMORY)?;
stack_pin_init!(let alloc = RegionAllocator::init_with_pool(pool));
// Add regions to the pool which can be allocated from
// [3GB, 4GB)
alloc.add_region(RegionSpan { base: 0xC000_0000, size: 0x4000_0000 }, AllowOverlap::No)?;
// [256GB, 257GB)
alloc.add_region(RegionSpan { base: 0x40_0000_0000, size: 0x4000_0000 }, AllowOverlap::No)?;
// Grab some specific regions out of the available regions.
// [3GB + 1MB, 3GB + 2MB)
let r1 = alloc.get_region_specific(RegionSpan { base: 0xC010_0000, size: 0x10_0000 })?;
// [256GB + 1MB, 256GB + 2MB)
let r2 = alloc.get_region_specific(RegionSpan { base: 0x40_0010_0000, size: 0x10_0000 })?;
// Grab some pointer aligned regions of various sizes
let r3 = alloc.get_region_pointer_aligned(1024)?;
let r4 = alloc.get_region_pointer_aligned(75)?;
let r5 = alloc.get_region_pointer_aligned(80000)?;
// Grab some page aligned regions of various sizes
let r6 = alloc.get_region(1024, 4 << 10)?;
let r7 = alloc.get_region(75, 4 << 10)?;
let r8 = alloc.get_region(80000, 4 << 10)?;
// Access base and size:
assert_eq!(r3.size(), 1024);
assert_eq!(r8.size(), 80000);
// No need to clean up. Regions will automatically be returned to the
// allocator as they go out of scope. Then the allocator will return all of
// its available regions to the pool when it goes out of scope. Finally, the
// pool will free all of its memory as the allocator releases its reference
// to the pool.Structs§
- Region
- Region
Allocator - Region
Allocator MuClass - Region
Allocator MuFields - Region
Allocator MuFields Mut - Region
Allocator MuGuard - Region
Allocator MuToken Guard - Region
Allocator MuToken Guard Mut - Region
Key - Region
Pool - Region
Span - Sort
ByBase - Sort
BySize