diff --git a/current/PLAN-IO-UNIFY.md b/current/PLAN-IO-UNIFY.md index bf940445..320bcaca 100644 --- a/current/PLAN-IO-UNIFY.md +++ b/current/PLAN-IO-UNIFY.md @@ -48,7 +48,20 @@ just with the scheduler now reachable as `context.io`. doc, stale `fib_dispatch` comment. - **Resolved design decisions:** D1 = direct `impl Io for Scheduler` (chosen). D2 = `now_ms` returns the virtual `clock_ms` (deterministic) — a real-clock variant is later. D4 = deferred to Phase 3. -- **Open for Phase 2:** +- **Phase 2 — `async`/`await` colorblind over the fiber Io. DONE** (`967aed67`, hardened `ada8d162`). + `async` heap-allocs a `*Future`, boxes a completion closure in a monomorphic `ThunkBox`, and submits + via `io.spawn_raw` (inline under `CBlockingIo`, a fiber under the scheduler); `await` parks via + `suspend_raw` until ready. Protocol changed to `suspend_raw(park: *ParkToken)` (write-back of the + awaiter). Workers are nullary (call-site capture). Migrated 1805/1806; adopted `push .{ … }`. Lock: + example 1824 (deferral visible: `1 2 10 20 123`). Review fixed: one-awaiter `await` guard; documented + the Future allocator-lifetime contract + that `cancel` doesn't stop an already-spawned worker (Phase 3). + - **Resolved D2 (ParkToken):** `suspend_raw(*ParkToken)` write-back (chosen over a registry). **ready() + liveness (CONCERN 6):** safe for single async/await (awaiter is suspended, not reaped, when readied); + `race` fan-in must still deregister (Phase 4). + - **Carried to convergence:** `async` should capture the scheduler's long-lived allocator (like + `sched.go`'s `own_allocator`) instead of the call-site `context.allocator` — needs a protocol + affordance; documented as a contract for now. +- **Open for later phases:** - **ParkToken↔fiber binding.** `ready(park)` needs `park.handle` = the awaiter `*Fiber`. The scheduler knows `self.current` at suspend; the cleanest is `suspend_raw(park: *ParkToken)` writing `park.handle = self.current` before parking (a small protocol change: the materializer installs