Files
lab-rv32i-freertos-task-wra…/doc/card-plan.md
T

81 lines
3.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# K07 — TaskHandle_t, explicit start and static trampoline
## Position
- Series: FreeRTOS C++
- Lesson: L06, card K07
- Duration: 30 minutes
- One C++ owner object plus one raw verifier task
- Dynamic FreeRTOS TCB/stack from real `heap_4.c`
K02 introduced CRTP in a larger first-task experiment. K07 revisits the task
boundary after the memory/resource cards and demands a precise identity proof:
object, TCB/handle and task stack are separate things with separate lifetimes.
## Outcome
After 30 minutes the student can annotate every argument of `xTaskCreate`,
explain why construction and start are separate, trace `void*` back to a typed
member body, and prove stable object address without virtual dispatch.
## Lesson plan — 30 minutes
| Time | Mode | Evidence |
| --- | --- | --- |
| 05 | predict addresses | object vs handle/TCB vs task stack |
| 510 | explicit start | constructor heap delta 0; start creates kernel objects |
| 1016 | C boundary | annotate entry, name, words, context, priority, handle-out |
| 1621 | trampoline | raw context equals object; static cast; private `run()` |
| 2126 | lifecycle | ready/running/completed, handle cleared, self-delete |
| 2630 | GDB/exit | stack local inside bounds; no move/vtable/destructor delete |
## Stable identity contract
```text
object_before == object_after_start
== xTaskCreate context
== trampoline context
== this in run
== completed object
handle_after_start == current handle == TCB address
handle_after_start != C++ object address
local variable address lies in task stack bounds
```
## Why explicit start
The derived object is not complete while its base constructor runs. Starting
there could let the scheduler enter `run()` against an incompletely constructed
object. `start()` is a separate state transition invoked only after the complete
owner exists. Duplicate start is rejected without another `xTaskCreate` call.
## Wrapper contract
- constructor stores name, stack words and priority only;
- `start()` moves `constructed -> starting -> ready` and calls the C API;
- static trampoline sets `running`, invokes `Derived::run()`, then records
`completed`, clears the handle and deletes the current kernel task;
- copy and move are deleted because the context address must not change;
- no destructor force-deletes a live task.
## Acceptance
- host test proves no constructor create call, one explicit create, stable
context, duplicate rejection and `start_failed` behavior;
- ABI contains the static trampoline but no vtable/RTTI/hosted runtime;
- Hazard3 shows object outside `ucHeap`, TCB in `ucHeap`, stack-local inside
reported task stack bounds;
- counter result is 500500, wrapper ends completed with null handle;
- all identity equalities and checkpoint 12 PASS hold.
## Main traps
1. `TaskHandle_t` is not the C++ object pointer; it identifies the TCB.
2. Stack depth is in `StackType_t` words, not necessarily bytes.
3. Moving a started wrapper invalidates the kernel's stored context.
4. Starting in a constructor exposes a partial object.
5. Hiding forced deletion in a destructor does not unwind arbitrary task-local
C++ objects and creates unsafe asynchronous lifetime coupling.