feat: async/await colorblind over the fiber Io (Phase 2 of Io unification)
`context.io.async(worker)` / `await` now run over the `Io` PROTOCOL, so the
same code interleaves under the fiber scheduler or runs inline under the
blocking `CBlockingIo` — one async stack, reached purely through `context.io`.
- Protocol: `suspend_raw(park: *ParkToken)` (was by-value). A suspending impl
records the parked execution context into `park.handle` before parking, so a
cross-context `ready(park)` knows whom to resume; `Scheduler.suspend_raw`
writes `self.current`, `CBlockingIo` ignores it.
- io.sx async layer rewritten colorblind: `async` submits the worker through
`io.spawn_raw` (inline under blocking, a fiber under the scheduler) and returns
a HEAP `*Future($R)` the worker fills later; `await` suspends via `suspend_raw`
until ready, then returns/raises. The generic worker is bridged to spawn_raw's
raw `(*void)->void` entry via a monomorphic `ThunkBox` (a heap-boxed nullary
completion closure) — all genericity lives in the closure env. Workers are
nullary (inputs captured at the call site) because a variadic pack can't cross
the fiber boundary. `CBlockingIo.spawn_raw` now runs the worker inline.
- Migrated 1805/1806 to the nullary `*Future` form; retrofit 1822/1823 to the
`push .{ … }` partial-context literal (inherits allocator/data).
- The async machinery adds a few prelude types, shifting the type-name table —
40 `.ir` snapshots regenerated (no behavior change; only `.exit`/`.stdout`/
`.stderr` would signal that, and none changed).
Locked by examples/concurrency/1824 — two async tasks under the fiber Io, the
completion log proving deferral (1 2 then 10 20 then 123). Suite 829/0,
byte-identical aarch64-macOS host + aarch64-linux container.
This commit is contained in:
@@ -110,7 +110,12 @@ ParkToken :: struct {
|
||||
|
||||
Io :: protocol #inline {
|
||||
spawn_raw :: (self: *Self, entry: *void, arg: *void, opts: SpawnOpts) -> *void;
|
||||
suspend_raw :: (self: *Self, park: ParkToken) -> !;
|
||||
// `park` is IN/OUT: a suspending impl records the parked execution context
|
||||
// (e.g. the awaiter's fiber) into `park.handle` before parking, so a later
|
||||
// `ready(park)` — called from a DIFFERENT context (the worker that completes
|
||||
// the awaited task) — knows which context to resume. Passed by pointer for
|
||||
// exactly that write-back. `ready`/`arm_timer` read the recorded handle.
|
||||
suspend_raw :: (self: *Self, park: *ParkToken) -> !;
|
||||
ready :: (self: *Self, park: ParkToken);
|
||||
poll :: (self: *Self, deadline_ms: i64) -> i64;
|
||||
now_ms :: (self: *Self) -> i64;
|
||||
|
||||
Reference in New Issue
Block a user