fibers B1.3b: mmap guard-page fiber stacks (x86_64 switch sibling deferred)
Fiber stacks are now mmap'd with a PROT_NONE guard page at the low end: mmap a [guard | usable] region and mprotect the low 16KB page PROT_NONE, so a stack overflow faults at the guard boundary instead of silently corrupting a neighbor (design 8.1.1 — fixed stacks without a guard corrupt silently on overflow). Locked by examples/1809-concurrency-fiber-guard-stack.sx (aarch64-macos-pinned): guard armed: 1 (mprotect -> 0) + sum: 20100 (a fiber runs real recursion on the guarded stack and yields). The guard FIRING is validated manually (a fiber recursing past its 128KB stack faults with Bus error at region+GUARD, exit 134 via the sx crash handler) — not corpus-pinned, since a deliberate-overflow crash is host-fragile and a 'child faulted' fork test would not prove the boundary catch specifically. The x86_64 swap_context sibling is DEFERRED: sx build --target x86_64-macos mislinks on this arm64 host (object x86_64, link step arm64) and x86_64-linux can't run here, so it could only ship IR-only / unrun. For the highest- corruption-risk asm, shipping un-run / un-negative-controlled code violates the design 10.7 'correctness not existence' rule. SysV target notes (rbx/rbp/r12-r15 /rsp, no callee-saved XMM, rsp-carried return address) recorded for a future x86_64 host. Suite green 735/0.
This commit is contained in:
@@ -4,7 +4,25 @@ Companion to [PLAN-FIBERS.md](PLAN-FIBERS.md). Update after every step (one step
|
||||
per the cadence rule). New corpus category: `18xx` concurrency.
|
||||
|
||||
## Last completed step
|
||||
**B1.3a-2 — the context-switch STRESS GATE (design §10.7) — DONE + adversarially reviewed.**
|
||||
**B1.3b (mmap guard-page stacks) — DONE. x86_64 switch sibling DEFERRED (not runnable on this
|
||||
host).** Fiber stacks are now `mmap`'d with a `PROT_NONE` GUARD PAGE at the low end (§8.1.1: a
|
||||
fixed stack without a guard silently corrupts neighbors on overflow). `mmap` the `[guard |
|
||||
usable]` region, `mprotect` the low 16KB page `PROT_NONE`; SP descends into the guard and faults
|
||||
loudly at the boundary instead of corrupting a neighbor. Locked by
|
||||
`examples/1809-concurrency-fiber-guard-stack.sx` (aarch64-macos-pinned): `guard armed: 1`
|
||||
(`mprotect`→0) + `sum: 20100` (a fiber runs real recursion on the guarded stack + yields).
|
||||
- **Guard FIRING validated** (manually, not corpus-pinned — a deliberate overflow crash is
|
||||
host-fragile): a fiber recursing past its 128KB stack faults with `Bus error` at the guard page
|
||||
(`region+GUARD`); the sx crash handler turns it into exit 134. Documented in the example header.
|
||||
- **x86_64 `swap_context` sibling DEFERRED:** `sx build --target x86_64-macos` mislinks on this
|
||||
arm64 host (object is x86_64 but the link step targets arm64), and `--target x86_64-linux` can't
|
||||
run here either — so the x86_64 switch could only ship IR-only, UNRUN. For the single
|
||||
highest-corruption-risk asm, shipping un-run/un-negative-controlled asm violates the §10.7
|
||||
"correctness not existence" rule. Deferred until an x86_64 host (or working cross-run) is
|
||||
available. The aarch64 switch + its §10.7 gate are complete and reviewed; portability is the
|
||||
only gap. SysV target notes recorded in Next step.
|
||||
|
||||
### Earlier — B1.3a-2 — the context-switch STRESS GATE (design §10.7) — DONE + adversarially reviewed
|
||||
The explicit every-callee-saved-register scribble that B1.3a-1 owed. `swap_context` now saves the
|
||||
COMPLETE AAPCS64 callee-saved set — integer x19-x28 + fp/lr + sp AND FP **d8-d15** (per §6.1.2
|
||||
only the low 64 bits of v8-v15 are callee-saved, so `d8-d15` is exactly sufficient; x18 is Apple's
|
||||
@@ -221,33 +239,29 @@ fibers/Io/scheduler code yet. Grounded floor facts:
|
||||
boundary; a sharper sx diagnostic for it is a candidate polish, not a blocker.
|
||||
|
||||
## Next step
|
||||
**B1.3b — the x86_64 switch sibling + `mmap` guard-page stacks.** The aarch64 switch + the §10.7
|
||||
gate (B1.3a) are done + reviewed. Sequence:
|
||||
1. **B1.3b-1 (x86_64 `swap_context`):** the per-arch sibling — System V callee-saved is
|
||||
rbx/rbp/r12/r13/r14/r15 + rsp (6 GP + sp; NO callee-saved XMM on the SysV C ABI, unlike Win64),
|
||||
so a different slot count + a different `scribble_verify` reg set. Arch-gate it like the asm
|
||||
corpus (`x86_64-linux` run on a matching CI host, ir-only on this aarch64 mac — `.ir` required).
|
||||
Carry the same 2-fiber mutual-scribble gate + the negative-control discipline. (1802 is the
|
||||
x86_64 naked-asm template.)
|
||||
2. **B1.3b-2 (`mmap` guard-page stacks):** replace the `alloc_bytes` stack with `mmap` +
|
||||
`mprotect` the low page `PROT_NONE` (mandatory — a fixed stack without a guard silently
|
||||
corrupts neighbors on overflow, §8.1.1). Add an overflow-hits-guard test (deep recursion past
|
||||
the stack → SIGSEGV/SIGBUS at the guard, NOT silent corruption). `mmap`/`mprotect` via
|
||||
`extern "c"`.
|
||||
3. Then B1.3 (fiber runtime substrate) is done → **B1.4** (`Io` impls: blocking ✅ →
|
||||
deterministic-sim KEYSTONE → event-loop) and **B1.5** (M:1 scheduler) build the real scheduler
|
||||
on top, replacing the hand-bootstrapped ping-pong with `spawn`/`yield`/`resume`. The §10.7 gate
|
||||
(1808) must keep passing as the switch grows.
|
||||
Two open threads — pick by host availability:
|
||||
|
||||
**(A) x86_64 `swap_context` sibling — needs an x86_64 host (or a working cross-run).** The per-arch
|
||||
switch. SysV-AMD64 callee-saved = rbx, rbp, r12, r13, r14, r15 + rsp (6 GP + sp; **no** callee-saved
|
||||
XMM on SysV, unlike Win64) — so a 7-slot ctx and a different `scribble_verify` reg set. No link
|
||||
register: the return address rides each fiber's stack, so the switch is `mov [from],regs… ;
|
||||
mov rsp,[to+48] ; ret` (the final `ret` pops `to`'s saved return addr). Bootstrap: push
|
||||
`&_fib_tramp` onto the new stack and set saved rsp to it (16-align: at the trampoline's `call`,
|
||||
rsp must be ≡0 mod 16). Args rdi/rsi/rdx; result rax. Carry the SAME 2-fiber mutual-scribble gate
|
||||
+ negative-control discipline + adversarial review. **Must be RUN + negative-controlled on a
|
||||
matching host** — do NOT ship it ir-only/unrun (§10.7). (1802 is the x86_64 naked-asm template.)
|
||||
|
||||
**(B) B1.4 — `Io` impls (blocking ✅ → deterministic-sim KEYSTONE → event-loop).** The aarch64
|
||||
substrate (switch + §10.7 gate + guarded stacks) is enough to build the scheduler on. B1.4 builds
|
||||
the deterministic-sim `Io` (calibrated against blocking `Io` before trusting it — §8.1.3), then
|
||||
**B1.5** (M:1 scheduler) replaces the hand-bootstrapped ping-pong with real `spawn`/`yield`/
|
||||
`resume` over the switch. The §10.7 gate (1808) + the guarded-stack path (1809) must keep passing
|
||||
as the switch is wrapped into the scheduler.
|
||||
|
||||
**Deferred (do NOT block on these):** issue **0150** (`void` struct field SIGTRAP) — only
|
||||
`Future(void)`/`timeout`, which are B1.4. The **`::` callable-parameter feature** (named-fn
|
||||
async workers `async(read_a, conn)`) — WIP at `.sx-tmp/wip-callable-params/patch.diff` (parser
|
||||
done, inference incomplete); a dedicated effort; lambda workers are the B1.2 idiom meanwhile.
|
||||
|
||||
**Deferred (do NOT block on these):** issue **0150** (`void` struct field SIGTRAP) — only
|
||||
`Future(void)`/`timeout`, which are B1.4. The **`::` callable-parameter feature** (named-fn
|
||||
async workers `async(read_a, conn)`) — WIP at `.sx-tmp/wip-callable-params/patch.diff` (parser
|
||||
done, inference incomplete); a dedicated effort; lambda workers are the B1.2 idiom meanwhile.
|
||||
`Future(void)`/`timeout` (B1.4). The **`::` callable-parameter feature** (named-fn async workers
|
||||
`async(read_a, conn)`) — WIP at `.sx-tmp/wip-callable-params/patch.diff` (parser done, inference
|
||||
incomplete); a dedicated effort; lambda workers are the idiom meanwhile.
|
||||
|
||||
`Context` layout settled: `{ allocator; data; io; }` (allocator index 0 fixed by
|
||||
`call.zig:1229`, io last). Io protocol + materializers + push-inherit are LANDED + reviewed.
|
||||
@@ -425,3 +439,16 @@ done, inference incomplete); a dedicated effort; lambda workers are the B1.2 idi
|
||||
(spec-correct for a call-boundary swap; in the example header): FPCR/FPSR/NZCV + TPIDR/TLS not
|
||||
swapped, fp=0 blocks unwind — relevant at N×M:1 / signals, not here. Suite green 734/0.
|
||||
Next: B1.3b (x86_64 sibling + mmap guard-page stacks).
|
||||
- **B1.3b — mmap guard-page stacks (x86_64 sibling deferred).** Fiber stacks now `mmap` a
|
||||
`[guard | usable]` region and `mprotect` the low 16KB page `PROT_NONE`, so a stack overflow
|
||||
faults at the guard boundary instead of silently corrupting a neighbor (§8.1.1). Locked by
|
||||
`examples/1809-concurrency-fiber-guard-stack.sx` (aarch64-macos-pinned): `guard armed: 1`
|
||||
(`mprotect`→0) + `sum: 20100` (a fiber runs real recursion on the guarded stack + yields).
|
||||
Guard FIRING validated manually (overflow → `Bus error` at `region+GUARD`, exit 134 via the sx
|
||||
crash handler) — not corpus-pinned because a deliberate-overflow crash is host-fragile (and a
|
||||
mere "child faulted" fork test wouldn't prove the BOUNDARY catch). The x86_64 `swap_context`
|
||||
sibling was DEFERRED: `--target x86_64-macos` mislinks on this arm64 host and `x86_64-linux`
|
||||
can't run here, so it could only ship un-run/un-negative-controlled — which §10.7 forbids for the
|
||||
highest-risk asm. SysV target notes (rbx/rbp/r12-r15/rsp, no callee-saved XMM, rsp-carried return
|
||||
addr) recorded in Next step. Suite green **735/0**. Next: x86_64 sibling (needs an x86_64 host)
|
||||
OR B1.4 (`Io` impls / scheduler) on the proven aarch64 substrate.
|
||||
|
||||
Reference in New Issue
Block a user