code wiki / (root) / nx_hangprobe_gate.nx

nx_hangprobe_gate.nx source

↩ module page · 28 lines · 1646 B

1// nx_hangprobe_gate.nx -- a gate that DELIBERATELY HANGS, to prove /api/gate_run's deadline actually fires 2// AND reaps. license_tier: ORIGINAL 3// WHY THIS EXISTS: seq1425 said the deadline freed the CALLER but not the CHILDREN, turning a hang into a 4// leak. You cannot prove that fixed with a gate that exits on its own -- you need one that genuinely hangs. 5// SHAPE = the exact seq1383 incident: fork a GRANDCHILD that sleeps holding the inherited stdout write end, 6// then the gate itself sleeps past any sane deadline. That grandchild is the hard case: killing only the 7// direct child leaves the pipe open, so the parent's blocking read never sees EOF (tr_run_capture_to's own 8// header calls this out, which is why it closes wfd BEFORE forking its watchdog). 9// EXPECTED via POST /api/gate_run target=nx_hangprobe_gate&deadline_ms=3000: 10// verdict TIMEOUT, response returns in ~3s, and ZERO nx_hangprobe processes survive afterwards. 11// This gate NEVER passes -- it is a fixture, not a check. It is named *_gate only so gate_run will run it. 12import "nx_syscalls.nx" 13import "nx_gate.nx" 14 15func main() -> i64 { 16 gw("=== nx_hangprobe_gate: deliberately hanging fixture (expect the CALLER's deadline to kill me) ===\n" as *u8) 17 let pid: i64 = sys_fork() 18 if pid == 0 { 19 // GRANDCHILD: hold the inherited stdout write end open and sleep well past any deadline. 20 sys_sleep_ms(600000) 21 sys_exit(0) 22 } 23 gw(" spawned a grandchild holding stdout; now sleeping past the deadline\n" as *u8) 24 sys_sleep_ms(600000) 25 gw(" UNREACHABLE unless the deadline never fired\n" as *u8) 26 sys_exit(0) 27 return 0 28}