docs 22: Phase B scoping from the seam read (the sync/star crux)
The synchronous TOOL_MANAGER contract vs the star: Call() must run to first yield before returning, drain() refuses re-entry, and dispatch is not yet a context - the same knot from the other side, and why B+C+D are one commit. CALL_CONTEXT::Continue is a hand-rolled scheduler that should disappear rather than be ported. Phase A's grace-ring-over-capacity: 33 says B must fix coroutine LIFETIME, not just topology. Records the upstream-divergence decision B has to take first. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EarUW9DS1c1sSW4ZNrkGQS
This commit is contained in:
parent
586fbadfe9
commit
837bce9c0a
1 changed files with 37 additions and 0 deletions
|
|
@ -112,6 +112,43 @@ mark-ready-and-drain; a coroutine yields to the scheduler rather than to its res
|
|||
- `RunMainStack` must keep working — it is now "run on the scheduler's caller context".
|
||||
- Expect this to be most of the risk and most of the calendar time.
|
||||
|
||||
**Seam read in full after Phase A landed (2026-08-06) — the crux, stated precisely.**
|
||||
`TOOL_MANAGER`'s contract is SYNCHRONOUS and the star's is not, and that single
|
||||
mismatch is the phase:
|
||||
|
||||
- `dispatchInternal` does `st->cofunc->Call( st->initialEvent )` and then, on the very
|
||||
next line, `if( !st->cofunc->Running() ) finishTool( st )`
|
||||
(`common/tool/tool_manager.cpp:870-874`). So `Call` must run the coroutine to its
|
||||
first yield *before returning*. Same shape at `ShutdownTool` (`:592`) and the
|
||||
pending-wait resume (`:808`).
|
||||
- The star says a resume happens from a clean stack via `drain()`, and `drain()`
|
||||
deliberately refuses re-entry — a context calling it would turn the star into a
|
||||
cycle. But dispatch RUNS on a stack the scheduler may own (that is Phase D), so
|
||||
"Call → drain" is re-entrant by construction unless dispatch is already a context.
|
||||
This is the same knot doc 20 §3 measured from the other side, and it is why B, C
|
||||
and D cannot be separated.
|
||||
- `CALL_CONTEXT::Continue`'s `CONTINUE_AFTER_ROOT` loop
|
||||
(`coroutine.h:175-183`) is a second, hand-rolled scheduler: the coroutine jumps to
|
||||
the ROOT stack, the root runs `m_mainStackFunction`, then resumes the coroutine.
|
||||
Under the star this is just "park with a reason, let the scheduler run the functor,
|
||||
mark ready" — the loop should disappear rather than be ported.
|
||||
|
||||
**A Phase A measurement that changes B's shape:** `grace-ring-over-capacity: 33` —
|
||||
KiCad holds 30+ coroutines that never finished and whose owners are gone, and still
|
||||
jumps into them. Under the star every one needs a live context (128 KB + buffer each,
|
||||
vs libcontext's 512 K), so **B must fix the lifetime, not just the topology**: give
|
||||
`COROUTINE` an owning handle and destroy the context when the tool state is popped.
|
||||
The grace ring is the measurement of exactly how much that is worth, and it should
|
||||
fall out of the tree at the end of B, not survive into C.
|
||||
|
||||
**Divergence policy (§10 q4), now answerable:** Phase A touched KiCad only inside
|
||||
`thirdparty/libcontext` — vendored code, no upstream conflict. B is the first phase to
|
||||
restructure `coroutine.h` + `tool_manager.cpp`, which CLAUDE.md's "keep the fork close
|
||||
to upstream" rule makes a real cost. Decide before starting: either accept the
|
||||
divergence, or keep the star adapter entirely inside libcontext + `sched_context.h` and
|
||||
leave both KiCad files untouched, which is likely possible because the whole seam is
|
||||
`jump_fcontext` calls.
|
||||
|
||||
### Phase C — waits yield the owning context (3–5 d)
|
||||
|
||||
`wxWasmYieldUntil` becomes a context yield: look up the owner of the current stack (the
|
||||
|
|
|
|||
Loading…
Reference in a new issue