Skip to content

heap

A free-list allocator over regions the caller supplies.

FlintOS has no allocator, deliberately: static allocation is what gives an RTOS bounded latency and no fragmentation. This exists for one reason — Espressif’s radio blobs allocate constantly and cannot be linked without a heap — and it is meant to stay confined to them. Nothing in the kernel should call it.

Deliberately. A #[global_allocator] would make alloc:: available everywhere and turn “the kernel does not allocate” from a property into a convention that erodes. Callers hold a [Heap] and allocate from it explicitly, so every allocation site is visible in the source.

Each allocation carries an eight-byte header immediately before the payload:

block start payload
| |
v v
[ .. alignment padding .. ][ hdr ][ user bytes .. ][ .. slack .. ]
^^^^^
total: bytes in the whole block
back: distance from block start to hdr

back is what makes over-aligned allocations work without leaking. When aligning the payload leaves a gap too small to be its own free block, the gap is absorbed into the allocation and back records how to find the real start again at free time. Both fields are u32 so the header is eight bytes on the host and on a 32-bit target alike — the tests then exercise the same layout that ships.

The free list is singly linked, ordered by address, and stored inside the free blocks themselves. Address order is what makes coalescing on free an O(1) check against the two neighbours rather than a scan.

struct Heap { /* private fields */ }

A heap over one or more regions.

Not Sync: it holds raw pointers and does no locking of its own. A caller sharing one across tasks or cores must wrap it — see kernel::heap.

Implements: Default, Send

const ALIGN: usize;

Payload alignment floor. Eight bytes, so a u64 field is legally placed.

const HEADER: usize;

Bytes of bookkeeping before each payload.

const MIN_BLOCK: usize;

Smallest block that can sit on the free list, since a free block stores the list node in its own bytes. Sixteen covers both a 64-bit host and a 32-bit target, so behaviour does not differ between test and target.