code wiki / _hdl_build / nx_team_out_lock_gate.nx

nx_team_out_lock_gate.nx

buildroot/runtime/_hdl_build/nx_team_out_lock_gate.nx

12171 B280 linesdepth 3pulls 3 transitivereach 0 importersview sourcekind gate/prooftopic team
docsdependenciesstructsconstsfunctions

about

nx_team_out_lock_gate.nx -- REFEREE for the team_out.tsv concurrent-writer lock (WMS torn-write follow-on). Proves an rt_lock-serialized WRITE SESSION keeps a MULTI-LINE record block contiguous under concurrency, AND that the detector sees failure without the lock (mandatory neg-control). WHY a lock, not fa_appendz: express_lane writes a MULTI-LINE block (ACK lines + the SITREP block); per-line atomicity (fa_appendz) keeps each LINE intact but does NOT stop a second writer's lines from interleaving BETWEEN this writer's lines -> the block is shredded. The fix (this gate proves) is to hold rt_lock across the whole multi-line session so no other writer can slip a line in. GOOD lane: NWORKERS fork; each acquires rt_lock(GOODLOCK), writes NRECS records (each = L lines, each line emitted as a SEQUENCE of sys_write so it CAN tear), releases. Expect: ZERO torn lines AND ZERO block-contiguity breaks AND all N*NRECS*L lines present. BAD lane (NEG-CONTROL): identical, but NO lock -> concurrent workers interleave -> torn lines AND/OR block breaks MUST appear. If bad has none, the detector is worthless -> RED. A line is CLEAN iff it begins "BLK w=" AND the 4 bytes before '\n' are " END" AND exactly one "BLK w=" head AND its w field == its z field (the two wid copies bracket the line; an interleave splits them). A BLOCK BREAK = a clean line with s>0 whose immediately-preceding line is not the same (w,r) at s-1 (the block's L lines were not contiguous). Per-run unique /tmp paths. Self-log via the assembled single sys_write (fd is uncontended). GREEN(0) iff all hold. Sovereign: nx_registry_lock (rt_lock/rt_unlock; nx_syscalls transitive). license_tier: ORIGINAL

dependencies 1 imports · 0 importers

nx_registry_lock.nx nx_team_out_lock_gate.nx

imports: nx_registry_lock.nx

imported by: nobody (leaf or entry point)

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main sys_now_realtime_sec sys_mmap sys_clock_gettime_real tl_path tl_cat tl_catn spawn_all sys_fork worker rt_lock rt_writeint_fd sys_mmap ↻ sys_write rt_now sys_now_realtime_sec ↻ rt_readint sys_openat_rd sys_mmap ↻ sys_read sys_close rt_unlink sys_openat_append rt_unlock sys_close ↻ rt_unlink ↻ emit_line sys_wait4 scan sys_read_file sys_openat_rd ↻ sys_lseek sys_mmap ↻ sys_read ↻ sys_close ↻ head_count int_after so son sys_openat_append ↻

structs

none

consts

24const NWORKERS: i64 = 16
25const NRECS: i64 = 60
26const LPB: i64 = 4 // lines per record block
27const MAXLINES: i64 = 8192 // >= NWORKERS*NRECS*LPB (3840) with headroom

functions

29func so(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
called by 1: main
30func son(v: i64) -> i64
called by 1: main
39func tl_cat(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){dst[off+i]=s[i];i=i+1} return off+i }
called by 2: tl_pathmain
40func tl_catn(dst: *u8, off: i64, v: i64) -> i64
called by 2: tl_pathmain
48func tl_path(out: *u8, tag: *u8, epoch: i64, suffix: *u8) -> i64
called by 1: main calls 2: tl_cattl_catn
55func emit_line(fd: i64, wid: i64, r: i64, s: i64) -> i64
called by 1: worker
90func worker(path: *u8, lockpath: *u8, wid: i64, locked: i64) -> i64
106func spawn_all(path: *u8, lockpath: *u8, locked: i64) -> i64
called by 1: main calls 3: sys_forkworkersys_wait4
122func int_after(b: *u8, ls: i64, le: i64, tok: *u8, tlen: i64) -> i64
called by 1: scan
140func head_count(b: *u8, ls: i64, le: i64) -> i64
called by 1: scan
154func scan(path: *u8, wA: *i64, rA: *i64, sA: *i64, clA: *i64, outs: *i64) -> i64
222func main() -> i64