Files
lab-rv32i-freertos-heap-models/doc/card-plan.md
T

4.8 KiB
Raw Blame History

K05 — C++ heap bridge, heap models and HeapStats

Position

  • Series: FreeRTOS C++
  • Lesson: L04, card K05
  • Duration: 30 minutes
  • Runtime: real FreeRTOS V11.3.0 heap_4.c on Hazard3/RV32I
  • C++ mode: freestanding C++17, no exceptions, RTTI or hosted libstdc++
  • New surface: HeapStats, HeapWatermark, complete new/delete bridge

K03 proved one-owner RAII, while K05 now exposes the allocator policy and its metrics. It does not introduce runtime resource selection; K06 will build that on top of the explicit failure and alignment contract established here.

Outcome

After 30 minutes the student can choose among heap_1heap_5 for a stated memory topology/lifetime policy, enumerate all C++ allocation bridge forms, distinguish total free bytes from largest free block, and prove that minimum-ever free bytes retain history after current free returns to baseline.

Lesson plan — 30 minutes

Time Mode Evidence
05 choose policy justify heap scheme for three deployments
59 bridge trace new[] -> pvPortMalloc and delete[] -> vPortFree
914 predict draw A/B/C blocks and predicted stats after freeing A/C
1421 Hazard3 prove request < total, request > largest, failure
2126 coalescence free B; retry same request; inspect one free block
2630 history/exit baseline recovery versus minimum-ever history

Policy table

Scheme Free? Coalesce? Key deployment constraint
heap_1 no n/a monotonic startup allocation only
heap_2 yes no holes remain separate; fragmentation grows
heap_3 libc libc linker/compiler must provide a suitable heap
heap_4 yes yes one FreeRTOS-owned region
heap_5 yes yes regions defined in increasing address order before allocation

Student choices:

  1. All objects allocated once at startup, never deleted: heap_1 is a valid simplest policy.
  2. One freestanding RAM region, dynamic tasks/queues with deletion: heap_4.
  3. Two disjoint RAM banks that must both feed the kernel allocator: heap_5.

heap_3 is not treated as a portable freestanding default because it delegates storage and behavior to the compiler C library and linker heap.

Canonical experiment

baseline: [ free ........................................ ]
allocate: [ A 2K ][ B 4K ][ C 2K ][ free ............... ]
free A/C: [ free ][ B live ][ free + trailing free ...... ]
           total=12256, largest=10192, blocks=2
request 10193 -> FAIL (sum is enough, no individual block is)
free B:   [ one coalesced free block ..................... ]
retry 10193 -> SUCCESS
free retry -> current free returns to baseline
minimum-ever remains at the historical low

Exact values may change with alignment/header configuration. Assessment uses relations, except for the fixed requested payload sizes in the source.

Stable evidence contract

Evidence Required relation
C++ addresses three distinct, aligned addresses inside ucHeap
bridge counters allocations=3, deallocations=3, live=0
deallocation order A, C, B
fragmented stats free blocks >=2 and total > largest
failed request largest < request < total; successful allocations unchanged
coalesced stats free blocks=1; largest=current=baseline
retry same request succeeds inside ucHeap
final stats current=baseline, minimum-ever remains below current

Complete bridge contract

void* operator new(size_t);
void* operator new[](size_t);
void operator delete(void*) noexcept;
void operator delete[](void*) noexcept;
void operator delete(void*, size_t) noexcept;
void operator delete[](void*, size_t) noexcept;

Ordinary new is fail-fast in this course profile because exceptions are off. The recoverable experiment uses raw pvPortMalloc and checks nullptr.

Misconceptions

  1. Total free bytes do not imply one payload of that size can be allocated.
  2. Returning to the current-free baseline does not erase the minimum-ever watermark.
  3. heap_4 limits external fragmentation by coalescing; it cannot promise absence of all fragmentation while live blocks separate holes.
  4. A C++ bridge selects one heap domain; it does not merge five schemes.
  5. heap_3 inherits the C library/linker heap contract and is therefore not a self-contained freestanding answer.

Acceptance

  • host test verifies field mapping and current/peak watermark calculations;
  • ABI test finds all six allocation functions and no hosted C++ runtime;
  • Hazard3 reaches all seven checkpoints and PASS;
  • failure request lies strictly between largest block and total free bytes;
  • retry succeeds only after B is freed and blocks coalesce;
  • student chooses heap_1, heap_4 and heap_5 for the three stated scenarios and justifies each constraint.