code wiki / (root) / nx_proc_snapshot.nx

nx_proc_snapshot.nx

buildroot/runtime/nx_proc_snapshot.nx

12358 B246 linesdepth 2pulls 2 transitivereach 3 importersview sourcekind librarytopic proc
docsdependenciesstructsconstsfunctions

about

nx_proc_snapshot.nx -- ONE /proc walk answers EVERY liveness question (seq1318 root fix). THE DEFECT (measured 2026-07-30, source-grounded): nx_hostctl's proc_alive_by_name getdents-walks all of /proc and reads every /proc/<pid>/cmdline -- and it runs ONCE PER GUARDED SERVICE PER POLL. At ~25 guards x 951 processes that is ~23,775 cmdline reads per 15s poll (~1,585/s, ~4,750 syscalls/s) for LIVENESS ALONE, and it is a POSITIVE FEEDBACK LOOP: a fork storm inflates /proc, which inflates the scan, which inflates kernel time. Measured context-switch rate 81k-93k/s. THE FIX IS STRUCTURAL, NOT A TUNING KNOB: walk /proc ONCE, concatenate every cmdline into one blob, and answer all ~25 questions from memory with ZERO further syscalls. O(P) per poll, not O(S x P). A second, free property matters as much as the speed: every guard now reads the SAME INSTANT, so two guards can no longer disagree because they scanned at different times. THREE PROPERTIES MAKE IT SAFE BY CONSTRUCTION (not by caller discipline): 1. AGE-BOUNDED. ps_alive rebuilds when the snapshot is older than PS_MAX_AGE_MS. No call site has to remember to refresh; an answer can never be unboundedly stale even if a caller forgets. 2. INVALIDATED ON MUTATION. ps_invalidate() after any spawn/kill forecloses the one DANGEROUS staleness direction (snapshot says DEAD for a daemon that was just started -> a second spawn -> EADDRINUSE churn). Stale-says-ALIVE merely defers a restart one poll, which is benign. 3. FAIL-SAFE, NEVER FAIL-WRONG. Open failure or blob overflow returns PS_UNKNOWN, and the caller falls back to ps_alive_direct -- the exact pre-existing scan. Worst case is today's cost; a wrong answer is impossible. (A silent cap that answered "not alive" would kill live daemons.) ps_alive_direct is ALSO the gate's ORACLE: nx_proc_snapshot_gate proves snapshot == direct for every probed name, so the fast path is verified against the slow one rather than asserted. license_tier: ORIGINAL No hw writes (Rule 26). Importable (no main).

dependencies 1 imports · 2 importers

nx_syscalls.nx nx_proc_snapshot.nx nx_hostctl.nx nx_proc_snapshot_gate.nx

imports: nx_syscalls.nx

imported by: nx_hostctl.nxnx_proc_snapshot_gate.nx

structs

none

consts

29const PS_BLOBCAP: i64 = 4194304 // 4 MiB of cmdlines (~951 procs x ~100B measured = ~100KB; 40x headroom)
30const PS_DENTBUF: i64 = 65536 // getdents64 batch
31const PS_CLBUF: i64 = 8192 // per-pid cmdline read buffer (reused; never grows)
32const PS_PATHBUF: i64 = 256
33const PS_STATEN: i64 = 64 // state cells
34const PS_SEP: i64 = 1 // 0x01 record separator: not a legal byte of a process-name needle,
36const PS_MAX_AGE_MS: i64 = 5000 // rebuild if older (safety net; the poll refreshes explicitly)
37const PS_CONFIRM_AGE_MS: i64 = 250 // a NEGATIVE answer is only trusted from a snapshot this fresh
38const PS_UNKNOWN: i64 = 0 - 1 // "I cannot answer" -> caller MUST fall back (never guessed)
39const PS_ZERO: i64 = 48
40const PS_NINE: i64 = 57

functions

46func ps_init() -> i64
54func ps_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
56func ps_contains(hay: *u8, hn: i64, needle: *u8, nn: i64) -> i64
71func ps_read_cmdline(path: *u8, buf: *u8, cap: i64) -> i64
86func ps_build() -> i64
149func ps_invalidate() -> i64 { ps_init(); ps_st[3] = 0; return 0 }
called by 1: main calls 1: ps_init
151func ps_refresh() -> i64 { return ps_build() }
called by 2: cmd_supervisemain calls 1: ps_build
152func ps_valid() -> i64 { ps_init(); return ps_st[3] }
called by 1: main calls 1: ps_init
153func ps_count() -> i64 { ps_init(); return ps_st[2] }
called by 1: main calls 1: ps_init
154func ps_builds() -> i64 { ps_init(); return ps_st[4] } // build counter = the mechanical proof of the O(P) property
called by 1: main calls 1: ps_init
155func ps_blob_len() -> i64 { ps_init(); return ps_st[0] }
called by 1: main calls 1: ps_init
156func ps_age_ms() -> i64
called by 1: main calls 2: ps_initsys_now_realtime_ms
162func ps_fresh(max_age_ms: i64) -> i64
174func ps_alive_direct(needle: *u8) -> i64
220func ps_alive_snap(needle: *u8) -> i64
240func ps_alive_or_direct(needle: *u8) -> i64