90 lines
2.7 KiB
Markdown
90 lines
2.7 KiB
Markdown
# K07 — `TaskHandle_t`, explicit `start()` and static trampoline
|
||
|
||
K07 isolates the exact C/C++ task-entry boundary. A local `CounterTask` object
|
||
is constructed without touching the FreeRTOS heap. Only an explicit `start()`
|
||
calls `xTaskCreate()` and passes the stable object address as `void*` context.
|
||
The kernel later calls a static, non-virtual trampoline, which recovers the
|
||
typed object and invokes its private `run()` member.
|
||
|
||
```text
|
||
CounterTask object
|
||
-> start()
|
||
-> xTaskCreate(static trampoline, context=&object)
|
||
-> kernel chooses task
|
||
-> trampoline(void*)
|
||
-> static_cast<CounterTask*>(context)
|
||
-> object.run()
|
||
-> state=completed, handle=nullptr, vTaskDelete(nullptr)
|
||
```
|
||
|
||
The wrapper is non-copyable and non-movable because a live kernel task retains
|
||
its object address. The destructor does not attempt asynchronous task deletion.
|
||
|
||
## Three distinct address domains
|
||
|
||
The checked Hazard3 run records:
|
||
|
||
```text
|
||
C++ object = 0x800fffcc (local object on the retained main stack)
|
||
TCB/handle = 0x800038b0 (dynamic kernel object in ucHeap)
|
||
task stack = 0x800034a0..0x80003890
|
||
result = 500500
|
||
```
|
||
|
||
The object address remains identical before start, in `xTaskCreate` context,
|
||
inside the trampoline, inside `run()` and at completion. The numeric handle is
|
||
the TCB address and is deliberately different from the C++ object.
|
||
|
||
## Lifecycle evidence
|
||
|
||
| Point | Evidence |
|
||
| --- | --- |
|
||
| 1 | object constructed; heap unchanged; handle null |
|
||
| 2 | state `starting` inside explicit start |
|
||
| 3 | state `ready`; typed object passed as raw context |
|
||
| 4 | `xTaskCreate` returned; handle now identifies the TCB |
|
||
| 5 | scheduler not yet started; object still at same address |
|
||
| 6 | static trampoline receives the original object address |
|
||
| 7 | state `running` before member body |
|
||
| 8 | body records current handle, stack bounds and result |
|
||
| 10 | state `completed`, handle cleared, current task self-deletes |
|
||
| 11–12 | raw verifier checks identity/lifecycle and emits PASS |
|
||
|
||
## Build
|
||
|
||
```sh
|
||
make check
|
||
```
|
||
|
||
Expected summary:
|
||
|
||
```text
|
||
PASS host: explicit start, stable context, duplicate/failure states
|
||
PASS ABI: static trampoline; no vtable, RTTI or hosted runtime
|
||
PASS task01: explicit start + stable context + trampoline
|
||
```
|
||
|
||
## Debug
|
||
|
||
```gdb
|
||
b explicit_task_debug_checkpoint
|
||
p g_checkpoint_trace
|
||
p/x g_object_before_start
|
||
p/x g_trampoline_context
|
||
p/x g_run_this
|
||
p/x g_handle_after_start
|
||
p/x g_tcb_address
|
||
p/x g_stack_low
|
||
p/x g_stack_high
|
||
p/x g_stack_local
|
||
p g_counter_result
|
||
p g_task_wrapper_pass
|
||
```
|
||
|
||
## Scope boundary
|
||
|
||
K07 uses dynamic kernel storage only to study entry and identity. K08 compares
|
||
dynamic and caller-supplied static TCB/stack policies and the timing of idle-task
|
||
cleanup. A `Task` destructor still does not force-delete a running task.
|
||
|