code wiki / _hdl_build / nx_pulse_daemon.nx

nx_pulse_daemon.nx source

↩ module page · 145 lines · 7135 B

1// nx_pulse_daemon.nx -- the CONDUCTOR'S LOOP, armed: re-runs nx_team_pulse on a schedule so every 2// role's evidence (triage, prove-all, security, examiner, scorecard) refreshes WITHOUT a human or 3// Claude asking. This is the unit the scorecard's "run on the loop" race-to-exceed names, made real. 4// - interval from knowledge/status/pulse_daemon.conf (I row; data-driven, no magic numbers) 5// - each beat: fork+exec the DURABLE runner _offc/nx_sov_build_run.elf nx_team_pulse 6// (runner rebuilds from settled source -> a /tmp wipe self-heals on the next beat) 7// - beat output appended to knowledge/status/pulse_daemon.out; one DAEMON-BEAT line per beat 8// to knowledge/status/pulse_daemon.log (epoch + pulse rc) = the durable heartbeat trend 9// - self-daemonizes (fork, parent exits, child setsid) so any caller returns immediately 10// - duplicate guard via knowledge/status/pulse_daemon.pid + /proc/<pid>/cmdline check 11// Sovereign (syscalls only, no .sh). Run from nxc2 root. license_tier: ORIGINAL 12import "nx_syscalls.nx" 13import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 14const K_MAGIC_4096: i64 = 4096 15const K_MAGIC_4080: i64 = 4080 16func _p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 17// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 18// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 19// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 20// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 21func _pn(v: i64) -> i64 { nxi_out(v); return 0 } 22func _fp(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 } 23// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 24// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 25// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 26// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 27func _fn(fd: i64, v: i64) -> i64 { nxi_fd(fd, v); return 0 } 28func pd_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 29func pd_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 } 30func pd_read_all(path: *u8, buf: *u8, cap: i64) -> i64 { 31 let fd: i64 = sys_openat_rd(path) 32 if fd < 0 { return 0 } 33 var n: i64 = 0 34 var go: i64 = 1 35 while go == 1 { let base: i64 = buf as i64; let r: i64 = sys_read(fd, (base + n) as *u8, cap - n); if r <= 0 { go = 0 } else { n = n + r } if n >= cap { go = 0 } } 36 sys_close(fd) 37 return n 38} 39func pd_contains(hay: *u8, n: i64, pat: *u8) -> i64 { 40 let pl: i64 = pd_len(pat) 41 if pl == 0 { return 0 } 42 var i: i64 = 0 43 while i + pl <= n { 44 var k: i64 = 0 45 var hit: i64 = 1 46 while k < pl { if hay[i+k] != pat[k] { hit = 0; k = pl } else { k = k + 1 } } 47 if hit == 1 { return 1 } 48 i = i + 1 49 } 50 return 0 51} 52// sleep secs via clock_nanosleep CLOCK_REALTIME rel (the proven supervisor idiom) 53func pd_sleep(secs: i64) -> i64 { 54 let ts: *i64 = sys_mmap(16) as *i64 55 ts[0] = secs 56 ts[1] = 0 57 return __syscall(SYS_CLOCK_NANOSLEEP, 0, 0, ts, 0, 0, 0) 58} 59// interval from conf 'I <sec>' row; 0 if conf/row absent (caller fails loud) 60func pd_interval() -> i64 { 61 let buf: *u8 = sys_mmap(K_MAGIC_4096) 62 let n: i64 = pd_read_all("knowledge/status/pulse_daemon.conf" as *u8, buf, K_MAGIC_4080) 63 var i: i64 = 0 64 while i < n { 65 var le: i64 = i 66 var scan: i64 = 1 67 while scan == 1 { 68 if le >= n { scan = 0 } 69 else { if buf[le] == (10 as u8) { scan = 0 } else { le = le + 1 } } 70 } 71 if buf[i] == (73 as u8) { 72 var v: i64 = 0 73 var q: i64 = i + 2 74 while q < le { 75 if buf[q] >= (48 as u8) { if buf[q] <= (57 as u8) { v = v * 10 + ((buf[q] as i64) - 48) } } 76 q = q + 1 77 } 78 return v 79 } 80 i = le + 1 81 } 82 return 0 83} 84// is a prior daemon still alive? pidfile -> /proc/<pid>/cmdline contains our name 85func pd_already_running() -> i64 { 86 let pbuf: *u8 = sys_mmap(64) 87 let pn: i64 = pd_read_all("knowledge/status/pulse_daemon.pid" as *u8, pbuf, 32) 88 if pn <= 0 { return 0 } 89 let path: *u8 = sys_mmap(256) 90 var o: i64 = 0 91 o = pd_cat(path, o, "/proc/" as *u8) 92 var i: i64 = 0 93 while i < pn { if pbuf[i] >= (48 as u8) { if pbuf[i] <= (57 as u8) { path[o] = pbuf[i]; o = o + 1 } } i = i + 1 } 94 o = pd_cat(path, o, "/cmdline" as *u8); path[o] = 0 as u8 95 let cbuf: *u8 = sys_mmap(512) 96 let cn: i64 = pd_read_all(path, cbuf, 500) 97 if cn <= 0 { return 0 } 98 return pd_contains(cbuf, cn, "nx_pulse_daemon" as *u8) 99} 100// one beat: run the durable runner on nx_team_pulse, stdout+stderr -> pulse_daemon.out; return rc 101func pd_beat() -> i64 { 102 let pid: i64 = sys_fork() 103 if pid == 0 { 104 let runner: *u8 = "_offc/nx_sov_build_run.elf" as *u8 105 let argv: *i64 = sys_mmap(32) as *i64 106 argv[0] = runner as i64; argv[1] = "nx_team_pulse" as *u8 as i64; argv[2] = 0 107 let envp: *i64 = sys_mmap(16) as *i64; envp[0] = 0 108 let ofd: i64 = sys_openat_append("knowledge/status/pulse_daemon.out" as *u8, 0x1a4) 109 if ofd >= 0 { sys_dup3(ofd, 1, 0); sys_dup3(ofd, 2, 0) } 110 sys_execve(runner, argv, envp) 111 sys_exit(127) 112 } 113 let st: *i64 = sys_mmap(16) as *i64 114 sys_wait4(pid, st, 0) 115 if (st[0] % 128) != 0 { return 0 - 1 } 116 return (st[0] >> 8) & 0xff 117} 118func main() -> i64 { 119 let interval: i64 = pd_interval() 120 if interval <= 0 { _p("nx_pulse_daemon: conf MISSING/invalid (knowledge/status/pulse_daemon.conf I row) -- fail loud\n" as *u8); sys_exit(1); return 1 } 121 if pd_already_running() == 1 { _p("nx_pulse_daemon: ALREADY-RUNNING (pidfile live) -- not starting a duplicate\n" as *u8); sys_exit(0); return 0 } 122 // daemonize: parent exits so the caller (runner/scheduler) returns; child owns the loop 123 let pid: i64 = sys_fork() 124 if pid != 0 { 125 _p("nx_pulse_daemon: ARMED pid=" as *u8); _pn(pid); _p(" interval=" as *u8); _pn(interval); _p("s (beats -> knowledge/status/pulse_daemon.log)\n" as *u8) 126 let pfd: i64 = sys_openat_wr("knowledge/status/pulse_daemon.pid" as *u8, 0x1a4) 127 if pfd >= 0 { _fn(pfd, pid); sys_close(pfd) } 128 sys_exit(0) 129 return 0 130 } 131 nx_setsid() 132 var go: i64 = 1 133 while go == 1 { 134 let rc: i64 = pd_beat() 135 let lfd: i64 = sys_openat_append("knowledge/status/pulse_daemon.log" as *u8, 0x1a4) 136 if lfd >= 0 { 137 _fp(lfd, "DAEMON-BEAT epoch=" as *u8); _fn(lfd, sys_now_realtime_sec()) 138 _fp(lfd, " pulse_rc=" as *u8); _fn(lfd, rc) 139 if rc == 0 { _fp(lfd, " verdict=GREEN\n" as *u8) } else { _fp(lfd, " verdict=ATTENTION\n" as *u8) } 140 sys_close(lfd) 141 } 142 pd_sleep(interval) 143 } 144 return 0 145}