Files
sx/examples/concurrency/1817-concurrency-fiber-m1-end-to-end.sx
agra 5949a88439 fibers: end-to-end M:1 capstone (B1.5) — Stream B1 complete
1817 composes the whole colorblind pure-sx async stack: the M:1
scheduler, suspending go/wait async, and deterministic virtual-time
sleep/now_ms, over the naked swap_context on guarded mmap stacks. A
coordinator launches three async tasks (sleep 30/10/20 -> return
100/20/3), awaits all three in spawn order, and sums them; tasks
complete in DEADLINE order (task 2@10, 3@20, 1@30), sum 123, final
virtual clock 30 -- fully deterministic.

Stream B1 (fibers + Io + M:1 scheduler) is feature-complete: examples
1800-1817, suite 755/0. Checkpoint + plan marked COMPLETE; next carve
is Stream B2 (channels / cancel / async stdlib).
2026-06-21 19:43:22 +03:00

67 lines
2.8 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Stream B1 (fibers) B1.5 — the M:1 colorblind async stack, end-to-end.
//
// One program exercises the whole pure-sx runtime together: the M:1 scheduler
// (B1.5a), the suspending fiber-task async layer `go`/`wait` (B1.4a), and the
// deterministic virtual-time timers `sleep`/`now_ms` (B1.4b) — all over the
// `abi(.naked)` `swap_context` on guarded `mmap` stacks (B1.0B1.3).
//
// A coordinator fiber launches three async tasks; each `sleep`s a different
// duration, records its completion (id @ virtual-ms) into a shared log, then
// returns a value. The coordinator `wait`s on all three (in SPAWN order) and
// sums their results. Because tasks complete in DEADLINE order — not spawn
// order, not await order — the completion log is the deterministic contract:
//
// task A: sleep 30 → returns 100
// task B: sleep 10 → returns 20
// task C: sleep 20 → returns 3
// completion order (by deadline): B@10, C@20, A@30
// coordinator awaits A,B,C → sum = 123, final virtual clock = 30
//
// `wait(A)` parks the coordinator until A finishes at t=30; B and C finish
// earlier (at 10 and 20) and are already `.ready` by the time their `wait`s run,
// so they return without re-parking — the values are correct regardless of await
// order, while the timer-driven schedule fixes the completion ORDER. Fully
// deterministic + reproducible (virtual time, no real clock).
//
// aarch64-macOS-pinned (the scheduler's per-arch asm + Apple mmap constants):
// runs end-to-end on a matching host, ir-only on a mismatch.
#import "modules/std.sx";
sched :: #import "modules/std/sched.sx";
Log :: struct { id: [8]i64; at: [8]i64; n: i64; }
rec :: (l: *Log, id: i64, at: i64) { l.id[l.n] = id; l.at[l.n] = at; l.n = l.n + 1; }
main :: () -> i64 {
lg : Log = ---; lg.n = 0;
s := sched.Scheduler.init();
ps := @s; pl := @lg;
// The coordinator runs as a fiber so `wait` has a `current` to park.
s.spawn(() => {
// Launch three async tasks; each sleeps, logs its completion, returns.
a := ps.go(() -> i64 => { ps.sleep(30); rec(pl, 1, ps.now_ms()); 100 });
b := ps.go(() -> i64 => { ps.sleep(10); rec(pl, 2, ps.now_ms()); 20 });
c := ps.go(() -> i64 => { ps.sleep(20); rec(pl, 3, ps.now_ms()); 3 });
// Await in SPAWN order; results come back correct regardless.
va := a.wait() or { -1 };
vb := b.wait() or { -1 };
vc := c.wait() or { -1 };
sum := va + vb + vc;
rec(pl, 9, sum); // sentinel row: id=9 carries the sum in `at`
});
s.run();
print("completion order (id @ virtual-ms):\n");
i := 0;
while i < lg.n {
if lg.id[i] == 9 { print("sum: {}\n", lg.at[i]); }
else { print(" task {} @ {}ms\n", lg.id[i], lg.at[i]); }
i = i + 1;
}
print("final virtual clock: {}ms\n", s.now_ms());
print("tasks: {}\n", s.n_spawned);
return 0;
}