`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.
30 lines
1.2 KiB
Plaintext
30 lines
1.2 KiB
Plaintext
// B1.2 / B2 — the async ergonomic layer over the `Io` capability, blocking
|
|
// default. `context.io.async(worker)` submits a NULLARY `worker: Closure() -> $R`
|
|
// and returns a `*Future($R)` handle; under the blocking `CBlockingIo` the worker
|
|
// runs to completion inline, so the Future is born `.ready`. `f.await()` yields
|
|
// the result (a value-failable `($R, !IoErr)`, handled with `or`).
|
|
// `context.io.now_ms()` reads the clock through the same capability.
|
|
//
|
|
// Worker form: a nullary lambda capturing any inputs at the CALL SITE
|
|
// (`() -> i64 => compute(a, b)`) — the colorblind shape that also works when the
|
|
// worker is deferred onto a fiber (a captured variadic pack can't cross the fiber
|
|
// boundary), mirroring `sched.go`.
|
|
#import "modules/std.sx";
|
|
|
|
main :: () {
|
|
// Inputs captured at the call site.
|
|
s := context.io.async(() -> i64 => 40 + 2);
|
|
print("sum: {}\n", s.await() or { -1 });
|
|
|
|
d := context.io.async(() -> i64 => 21 * 2);
|
|
print("double: {}\n", d.await() or { -1 });
|
|
|
|
// A worker that closes over a local.
|
|
base := 42;
|
|
n := context.io.async(() -> i64 => base);
|
|
print("nullary: {}\n", n.await() or { -1 });
|
|
|
|
// The Io capability also carries a clock.
|
|
if context.io.now_ms() >= 0 { print("clock ok\n"); }
|
|
}
|