code wiki / _hdl_build / nx_daemon_supervisor.nx

nx_daemon_supervisor.nx

buildroot/runtime/_hdl_build/nx_daemon_supervisor.nx

35763 B662 linesdepth 6pulls 7 transitivereach 0 importersview sourcekind tooltopic daemon
docsdependenciesstructsconstsfunctions

about

nx_daemon_supervisor.nx -- SOVEREIGN data-driven daemon supervisor. THE organ that makes daemon lifecycle the ecosystem's job, not Claude's: a daemon is a REGISTRY ROW (data), not compiled into a guard's target list and not nursed by a bash loop. Reads daemons.reg HOT every cycle, responds-health probes each via hp_probe (SERVING / HUNG / REFUSED -- catches the wedge that PID/port checks miss), and REVIVES the dead by fork+execve of the declared argv. 2-consecutive-fail discipline (in-memory, keyed by name) so a single transient probe never triggers a relaunch. On HUNG (wedged, holding the port) it kills the matching process first (the new instance could not bind otherwise), then launches. Zombies reaped every cycle (wait4 WNOHANG). Add a daemon = a registry line + reload -- NO recompile, NO shell. BOUNDED-VSZ DISCIPLINE (2026-07-16): every reusable buffer is allocated ONCE before the loop and reused each cycle. The hot loop performs ZERO sys_mmap. The prior version mmap'd per cycle -- fatally, it read the registry with sys_read_file, whose 4 GiB default cap (used whenever lseek can't size the file) maps 4 GiB of VSZ per cycle and never frees it. That drove VSZ to 116 GB in ~29 cycles, and under heuristic overcommit fork() then returns -ENOMEM (proven: REVIVED ... pid=-12), so revives silently stopped. The registry is now read into a fixed buffer via sys_read; ds_decw is temp-free; VSZ stays flat forever. daemons.reg (pipe-delimited; lines starting # or blank ignored; args are space-separated, no spaces-in-args): <name> | <cwd> | <argv0 [arg1 arg2 ...]> | <health_port> | <arm: revive|watch> health = hp_probe(port): ANY HTTP response on 127.0.0.1:port = healthy (401/404 count). revive = relaunch (and kill-the-wedge) on 2 consecutive non-SERVING probes; watch = detect+log only. license_tier: ORIGINAL module: nishi-core.ops.daemon_supervisor

dependencies 3 imports · 0 importers

nx_syscalls.nx nx_health_probe.nx nx_metrics_ring.nx nx_daemon_supervisor.nx

imports: nx_syscalls.nxnx_health_probe.nxnx_metrics_ring.nx

imported by: nobody (leaf or entry point)

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

main ds_log sys_openat_append sys_write ds_slen sys_close sys_mmap sys_mmap_shared sys_fork ds_status_server sys_socket sys_exit sys_mmap ↻ sys_setsockopt hp_sockaddr sys_bind sys_listen sys_accept sys_set_socket_timeout sys_mmap ↻ sys_setsockopt ↻ sys_munmap sys_read ds_sappend ds_decw sys_write ↻ sys_close ↻ sys_exit ↻ sys_wait4 sys_now_realtime_sec sys_mmap ↻ sys_clock_gettime_real ds_sappend ↻ ds_decw ↻ ds_read_reg sys_openat_rd sys_read ↻ sys_close ↻ ds_verify_reg sys_fork ↻

structs

none

consts

25const DS_MAGIC_1024: i64 = 1024
26const DS_MAGIC_65536: i64 = 65536
27const DS_MAGIC_65535: i64 = 65535
28const DS_MAGIC_8000: i64 = 8000
29const DS_MAGIC_2048: i64 = 2048
30const DS_MAGIC_2047: i64 = 2047
31const DS_MAGIC_10000: i64 = 10000
33const DS_REG: *u8 = "/volume1/homes/elderwesto/nishihost/daemons.reg" as *u8
34const DS_LOG: *u8 = "/volume1/homes/elderwesto/nishihost/daemon_supervisor.log" as *u8
35const DS_CYCLE_SEC: i64 = 15
36const DS_MAX: i64 = 64
37const DS_PROBE_TMO: i64 = 3
38const DS_REGCAP: i64 = 65536
39const DS_STATUS_PORT: i64 = 18095
40const DS_SHARED_SZ: i64 = 8192
41const DS_RING: *u8 = "metrics.ring" as *u8 // sovereign bounded TSDB the supervisor writes inline

functions

43func ds_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
44func ds_p(s: *u8) -> i64 { sys_write(1, s, ds_slen(s)); return 0 }
45func ds_log(s: *u8) -> i64
53func ds_decw(v: i64, out: *u8) -> i64
69func ds_read_reg(buf: *u8, cap: i64) -> i64
called by 1: main calls 3: sys_openat_rdsys_readsys_close
78func ds_sappend(dst: *u8, w: i64, s: *u8) -> i64
86func ds_next_line(buf: *u8, pos: i64, end: i64) -> i64
called by 1: main
93func ds_line_end(buf: *u8, pos: i64, end: i64) -> i64
called by 1: main
99func ds_field(buf: *u8, ls: i64, le: i64, idx: i64, out: *u8, cap: i64) -> i64
called by 1: main
126func ds_atoi(s: *u8) -> i64
131func ds_streq(a: *u8, b: *u8) -> i64
called by 1: main
139func ds_launch(cwd: *u8, cmd: *u8) -> i64
188func ds_kill_wedged(needle: *u8) -> i64
252func ds_resolve_bin(cwd: *u8, cmd: *u8, out: *u8) -> i64
called by 1: main
279func ds_exe_sweep(bin: *u8, mode: i64, dbuf: *u8, path: *u8, rl: *u8) -> i64
337func ds_exitcode(status: i64) -> i64
called by 1: ds_verify_reg
342func ds_verify_reg() -> i64
380func ds_status_server(shm: *u8) -> i64
432func main() -> i64