# Karta pracy: FreeRTOS `heap_4`

Trzy programy wspierające kartę po K&R 5.4 oraz `structures`:

1. nagłówek, wyrównanie i geometria splitu na arenie 256 B;
2. lista adresowa + scalanie `A | B | C`;
3. niezmodyfikowany FreeRTOS-Kernel V11.3.0 `heap_4.c`.

W lekcji 30-minutowej programy 1–2 są demonstracjami z predykcją. Uczeń
debugguje wyłącznie program 3.

Task 3 linkuje upstream `portable/MemMang/heap_4.c` z commita
`9b777ae5c5b8e9e456065a00294d1e5f5f9facf5`.

- AMD64: rzeczywisty algorytm + jednowątkowy adapter sekcji krytycznej.
- Hazard3: `tasks.c`, `list.c`, `heap_4.c` i oficjalny port RISC-V.
- RP2350: zgodny core+port z forka Raspberry Pi (`4f7299d6ea74`) oraz
  podstawiony stabilny allocator V11.3.0.

## Bezpośrednia kontynuacja K&R 5.4

Lekcja zaczyna się od gotowego projektu z poprzedniej karty:
`allocbuf[64]`, `allocp`, `alloc(5)`, `alloc(7)` oraz offsety
`0 -> 5 -> 12`. Ten alokator:

- nie potrafi zwolnić pierwszego bloku i zachować drugiego;
- nie przechowuje rozmiaru ani stanu zwróconego obszaru;
- nie zapamiętuje i nie wykorzystuje dziur;
- odzyskuje pamięć wyłącznie przez reset całej areny.

FC01 odpowiada na jedno pytanie projektowe: **co trzeba dodać, aby zwalniać
dowolny blok i ponownie wykorzystywać powstałe miejsce?** Odpowiedzią jest
mechanika `heap_4`: nagłówek bloku, lista wolnych bloków uporządkowana po
adresie, first-fit, split oraz scalanie fizycznych sąsiadów.

FreeRTOS udostępnia kilka wymiennych implementacji tego samego API i projekt
linkuje dokładnie jedną. `heap_1`, `heap_2`, `heap_3` i `heap_5` są w tej
karcie tylko jednominutową mapą kontekstu. Cała obserwowana implementacja to
niezmodyfikowany [`heap_4.c` z FreeRTOS-Kernel V11.3.0](https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/V11.3.0/portable/MemMang/heap_4.c).

Lekcja trwa 30 minut. Task 1 i Task 2 są krótkimi demonstracjami z predykcją;
Task 3 jest jedynym centralnym przebiegiem ucznia w debuggerze. Obraz dla
Pico 2 W musi być zbudowany i wgrany przed zajęciami. `heap_4` jest wyborem
linkera projektu, nie sprzętowym mechanizmem RP2350.

## Jedno wejście: `stemctl`

Centralny przebieg lekcji, przygotowany przed wejściem uczniów:

```bash
stemctl debug rp2350 freertos heap4 3 --device /dev/bus/usb/BBB/DDD
```

Pełna weryfikacja repozytorium wykonywana poza 30-minutową lekcją:

```bash
stemctl series cards fetch freertos heap4
stemctl test native-amd64 freertos heap4 1
stemctl test hazard3-sim freertos heap4 2
stemctl debug hazard3-sim freertos heap4 3
stemctl test rp2350 freertos heap4 3
stemctl deploy rp2350 freertos heap4 3 --device /dev/bus/usb/BBB/DDD
stemctl debug rp2350 freertos heap4 3 --device /dev/bus/usb/BBB/DDD
```

- `debug rp2350`: roboczy ELF `no_flash` ładowany do SRAM.
- `deploy rp2350`: trwały obraz w SPI flash, odczytany przez breakpointy.

## Kontrakt zadań

| Task | Sprawdza | Wynik kluczowy |
|---|---|---|
| 1 | alignment, header, split | `wanted + remainder == 256` |
| 2 | lista po adresie, coalescing | `2 bloki -> 1 blok`, `96 -> 144 B` |
| 3 | prawdziwe API FreeRTOS | free wraca do F0, minimum nie rośnie, OOM = NULL |

## Debugowanie Task 3

Automatyczny start: `heap4_reset_checkpoint`. Karta prowadzi po ośmiu
powtarzalnych stanach jednego procesu:

| Event | Symbol | Najważniejszy dowód Hazard3 |
|---|---|---|
| E01 | `heap4_reset_checkpoint` | `free=largest=4080`, 1 blok |
| E02 | `heap4_alloc_a_checkpoint` | A(24), `consumed=48`, `free=4032` |
| E03 | `heap4_alloc_b_checkpoint` | B(40), `consumed=64`, `free=3968` |
| E04 | `heap4_alloc_c_checkpoint` | C(16), `consumed=32`, `free=3936` |
| E05 | `heap4_free_a_checkpoint` | `free=3984`, 2 bloki |
| E06 | `heap4_fragmented_checkpoint` | `free=4016`, 2 bloki, `free>largest` |
| E07 | `heap4_coalesced_checkpoint` | `free=largest=4080`, 1 blok |
| E08 | `task03_debug_checkpoint` | OOM `NULL`, hook=1, asserts=0, PASS=1 |

`BlockLink_t` ma na RV32 8 B, ale port wymaga wyrównania 16 B, dlatego
`xHeapStructSize` wynosi 16 B. To rozróżnienie tłumaczy zużycie 48/64/32 B.

```gdb
p g_fragmented_stats
p g_final_stats
p g_a_consumed
p g_b_consumed
p g_c_consumed
p xFreeBytesRemaining
p xMinimumEverFreeBytesRemaining
p xStart
p pxEnd
x/160bx ucHeap
b prvInsertBlockIntoFreeList
b pvPortMalloc
b vPortFree
```

Scalanie sprawdzamy z replay E06: zatrzymujemy się przed `vPortFree(g_b)`,
ustawiamy tymczasowy breakpoint na `prvInsertBlockIntoFreeList` i krokujemy.
Upstream V11.3.0 scala najpierw poprzedni/lewy, a potem następny/prawy blok.
Pełna macierz kroków diagramów jest w
[`doc/hazard3-iteration-plan.md`](doc/hazard3-iteration-plan.md).

W UI: Termdebug po lewej; źródło i listing po prawej; bash pod Neovimem.
`F5` continue, `F9` breakpoint, `F10` next, `F11` step, `Shift-F11`
finish, `F8` stepi, `:StudentStack`, `:StudentMemory`, `:StudentLst`.

## Test repozytorium

```bash
./tests/test_host.sh
bash -n tools/card-action.sh
./scripts/render_pdf.sh
```

Źródło i licencja: [UPSTREAM.md](UPSTREAM.md).
