code wiki / _hdl_build / nx_pub_recover_exec_gate.nx

nx_pub_recover_exec_gate.nx source

↩ module page · 72 lines · 4285 B

1// nx_pub_recover_exec_gate.nx -- SOVEREIGN gate for the recovery EXECUTOR (real kill of a real process). 2// Spawns a live mock daemon (nx_pr_mock, distinct cmdline so no self-kill), confirms it's ALIVE, runs 3// pe_exec on a seeded PENDING queue, then proves: the mock is KILLED, the queue line flips PENDING->DONE, 4// the recovery is LEDGERED, and a re-run is a NO-OP (idempotent, no PENDING left). Per-run /tmp test files. 5// Requires /tmp/nx_pr_mock.sov.elf built first. license_tier: ORIGINAL 6import "nx_syscalls.nx" 7import "nx_pub_recover_exec.nx" // pe_exec + (transitively) proc_alive_by_name / pr_n / pr_s 8 9const GE_Q: *u8 = "/tmp/pe_test_queue.tsv" 10const GE_LED: *u8 = "/tmp/pe_test_ledger.tsv" 11const GE_MOCK: *u8 = "/tmp/nx_pr_mock.sov.elf" 12const GE_NEEDLE: *u8 = "nx_pr_mock" 13 14func ge_uw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 15func ge_wn(v: i64) -> i64 { let b: *u8=sys_mmap(24); let e: i64=pr_n(b,0,v); sys_write(1,b,e); return 0 } 16func ge_sleep_ms(ms: i64) -> i64 { let ts: *i64=sys_mmap(16) as *i64; ts[0]=ms/1000; ts[1]=(ms-(ms/1000)*1000)*1000000; __syscall(35, ts as i64, 0,0,0,0,0); return 0 } 17func ge_write(path: *u8, buf: *u8, len: i64) -> i64 { let fd: i64=sys_openat_wr(path, 0x1a4); if fd<0 {return 0-1} if len>0 { sys_write(fd, buf, len) } sys_close(fd); return 0 } 18 19func main(argc: i64, argv: *i64) -> i64 { 20 var pass: i64 = 0; var total: i64 = 0 21 22 // spawn the mock daemon 23 let pid: i64 = sys_fork() 24 if pid == 0 { 25 let av: *i64 = sys_mmap(16) as *i64; av[0]=GE_MOCK as i64; av[1]=0 26 let ev: *i64 = sys_mmap(8) as *i64; ev[0]=0 27 sys_execve(GE_MOCK, av, ev); sys_exit(127) 28 } 29 ge_sleep_ms(500) // let execve land 30 31 // T0: mock alive 32 let a0: i64 = proc_alive_by_name(GE_NEEDLE) 33 total = total + 1; if a0 == 1 { pass = pass + 1; ge_uw("[PASS] T0 mock spawned + ALIVE\n" as *u8) } else { ge_uw("[FAIL] T0 mock not alive (build /tmp/nx_pr_mock.sov.elf first)\n" as *u8) } 34 35 // seed a PENDING recovery request for the mock 36 let m: *u8 = sys_mmap(256); var o: i64 = 0 37 o = pr_s(m,o,"PENDING" as *u8); m[o]=9 as u8; o=o+1 38 o = pr_n(m,o, sys_now_realtime_sec()); m[o]=9 as u8; o=o+1 39 o = pr_s(m,o,GE_NEEDLE); m[o]=9 as u8; o=o+1 40 o = pr_s(m,o,"wedge" as *u8); m[o]=9 as u8; o=o+1 41 o = pr_n(m,o,20000); m[o]=10 as u8; o=o+1 42 ge_write(GE_Q, m, o) 43 ge_write(GE_LED, "" as *u8, 0) 44 45 // T1: execute recovery -> 1 46 let ex: i64 = pe_exec(GE_Q, GE_LED) 47 total = total + 1; if ex == 1 { pass = pass + 1; ge_uw("[PASS] T1 executed 1 recovery\n" as *u8) } else { ge_uw("[FAIL] T1 expected 1 got " as *u8); ge_wn(ex); ge_uw("\n" as *u8) } 48 ge_sleep_ms(400) // let SIGTERM land 49 50 // T2: mock KILLED 51 let a1: i64 = proc_alive_by_name(GE_NEEDLE) 52 total = total + 1; if a1 == 0 { pass = pass + 1; ge_uw("[PASS] T2 mock KILLED by proc_kill_by_name\n" as *u8) } else { ge_uw("[FAIL] T2 mock still alive\n" as *u8) } 53 let st: *i64 = sys_mmap(16) as *i64; sys_wait4(pid, st, 0) // reap 54 55 // T3: queue line PENDING -> DONE 56 let lp: *i64 = sys_mmap(16) as *i64; lp[0]=0; let qb: *u8 = sys_read_file(GE_Q, lp) 57 var done: i64 = 0; if (qb as i64)!=0 { if lp[0]>=4 { if qb[0]==(68 as u8) { done=1 } } } // 'D' of DONE 58 total = total + 1; if done == 1 { pass = pass + 1; ge_uw("[PASS] T3 queue line PENDING->DONE\n" as *u8) } else { ge_uw("[FAIL] T3 queue not DONE\n" as *u8) } 59 60 // T4: ledgered 61 let lp2: *i64 = sys_mmap(16) as *i64; lp2[0]=0; let lb: *u8 = sys_read_file(GE_LED, lp2) 62 var led: i64 = 0; if (lb as i64)!=0 { if lp2[0]>0 { led=1 } } 63 total = total + 1; if led == 1 { pass = pass + 1; ge_uw("[PASS] T4 recovery LEDGERED\n" as *u8) } else { ge_uw("[FAIL] T4 no ledger\n" as *u8) } 64 65 // T5: NEG-CONTROL re-run -> 0 (no PENDING left = idempotent, no double-kill) 66 let ex2: i64 = pe_exec(GE_Q, GE_LED) 67 total = total + 1; if ex2 == 0 { pass = pass + 1; ge_uw("[PASS] T5 idempotent re-run -> 0\n" as *u8) } else { ge_uw("[FAIL] T5 expected 0 got " as *u8); ge_wn(ex2); ge_uw("\n" as *u8) } 68 69 ge_uw("=== nx_pub_recover_exec_gate " as *u8); ge_wn(pass); ge_uw("/" as *u8); ge_wn(total) 70 if pass == total { ge_uw(" GREEN\n" as *u8); return 0 } 71 ge_uw(" RED\n" as *u8); return 1 72}