Skip to main content

Crate region_alloc

Crate region_alloc 

Source
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
RegionAllocator
RegionAllocatorMuClass
RegionAllocatorMuFields
RegionAllocatorMuFieldsMut
RegionAllocatorMuGuard
RegionAllocatorMuTokenGuard
RegionAllocatorMuTokenGuardMut
RegionKey
RegionPool
RegionSpan
SortByBase
SortBySize

Enums§

AllowIncomplete
AllowOverlap
TestRegionSet

Statics§

REGIONALLOCATOR_MU_STRING_REG