Files
sx/examples/concurrency/1822-concurrency-fiber-context-inherit.sx
agra 967aed67d4 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.
2026-06-27 07:50:29 +03:00

36 lines
1.5 KiB
Plaintext

// Stream B2/A1 — a fiber INHERITS the dynamic `context` in force when it was
// spawned. Previously a fiber body ran under the static `__sx_default_context`
// (the `abi(.c)` `fib_dispatch` dropped the implicit context), so a
// `push Context { … }` around `spawn` was invisible inside the fiber. Now
// `Scheduler.spawn` snapshots `context` into the fiber and `fib_dispatch`
// re-pushes it around the body — so a capability installed before `spawn`
// (here a marker in `context.data`) is visible to the worker.
//
// This is the foundation for folding a fiber scheduler behind `context.io`: a
// worker's `context.io.*` must resolve to the scheduler that spawned it, not the
// blocking default. Behavior-preserving for fibers spawned under the default
// context (the snapshot just re-pushes that same default).
//
// aarch64-pinned (the scheduler's per-arch asm): runs end-to-end on a matching
// host (macOS + linux), ir-only on a mismatch.
#import "modules/std.sx";
sched :: #import "modules/std/sched.sx";
Marker :: struct { id: i64; }
main :: () -> i64 {
mk := Marker.{ id = 7 };
s := sched.Scheduler.init();
ps := @s;
print("outside: marker id = {}\n", mk.id);
push .{ data = xx @mk } {
ps.spawn(() => {
m : *Marker = xx context.data; // inherited from the spawn-time context
print("inside fiber: context.data marker id = {}\n", m.id);
});
ps.run();
}
print("done\n");
return 0;
}