code wiki / _hdl_build / nx_job_runner.nx

nx_job_runner.nx source

↩ module page · 156 lines · 6515 B

1// nx_job_runner.nx -- the STANDING NISHI RUNNER (operator 2026-07-02: "stop using shell use the 2// nishi ecosystem"). Execution flows through the ECOSYSTEM: work is ENQUEUED as lines in 3// knowledge/store/nx_jobs.queue (authored by any tool/organ -- no shell), this daemon executes each 4// job via fork/execve on the sovereign harness or a prebuilt organ ELF, and RECEIPTS land in 5// knowledge/status/job_runner.log. The operator/agent reads receipts + the organs' own status logs. 6// After ONE bootstrap start, no human/agent shell commands are needed to run organs. 7// queue line formats: 8// run <organ> -> ./_offc/nx_sov_build_run.elf <organ> 9// runi <organ> -> ./_offc/nx_sov_build_run.elf <organ> --install 10// elf <name> [a1] [a2] [a3] -> ./_offc/<name>.elf a1 a2 a3 11// cursor = knowledge/store/nx_jobs.done (count of processed lines; missing = 0). 12// v1: single instance by convention (one bootstrap start); flock lease = the M4 follow-on. 13// license_tier: ORIGINAL 14import "nx_syscalls.nx" 15const K_MAGIC_2000: i64 = 2000 16const K_MAGIC_1024: i64 = 1024 17const K_MAGIC_2048: i64 = 2048 18 19const JQ: *u8 = "knowledge/store/nx_jobs.queue" 20const JD: *u8 = "knowledge/store/nx_jobs.done" 21const JL: *u8 = "knowledge/status/job_runner.log" 22 23func jl(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 24func ap(b: *u8, n: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){b[n+i]=s[i];i=i+1} return n+i } 25func apn(b: *u8, n: i64, v: i64) -> i64 { 26 let t: *u8=sys_mmap(28); var m: i64=v; var k: i64=0 27 if m<0 { b[n]=45 as u8; return apn(b, n+1, 0-m) } 28 if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} 29 var i: i64=0; var p: i64=n; while i<k{b[p]=t[k-1-i];p=p+1;i=i+1} return p } 30 31// read the cursor (processed-line count); 0 if absent 32func jr_cursor() -> i64 { 33 let box: *i64 = sys_mmap(16) as *i64 34 let b: *u8 = sys_read_file(JD, box) 35 if (b as i64)==0 { return 0 } 36 var v: i64 = 0 37 var i: i64 = 0 38 while i < box[0] { let c: i64 = b[i] as i64; if c>=48 { if c<=57 { v=v*10+(c-48) } } i=i+1 } 39 return v } 40 41func jr_cursor_set(v: i64) -> i64 { 42 let fd: i64 = sys_openat_wr(JD, 0x1a4) 43 if fd < 0 { return 0 - 1 } 44 let b: *u8 = sys_mmap(32) 45 let n: i64 = apn(b, 0, v) 46 sys_write(fd, b, n) 47 sys_close(fd) 48 return 0 } 49 50// execute one job line [ls..le) of buf; returns child exit code (or -errno-ish) 51func jr_exec(buf: *u8, ls: i64, le: i64, namebuf: *u8) -> i64 { 52 // tokenize (max 5) into NUL-terminated slots of namebuf (5 x 256) 53 var nt: i64 = 0 54 var i: i64 = ls 55 while i < le { 56 while i < le { if (buf[i] as i64)==32 { i=i+1 } else { i=le+1000 } } 57 if i > le { i = i - 1000 } 58 if i < le { 59 if nt < 5 { 60 var o: i64 = 0 61 while i < le { if (buf[i] as i64)!=32 { namebuf[nt*256+o]=buf[i]; o=o+1; i=i+1 } else { i=le+K_MAGIC_2000 } } 62 if i > le { i = i - K_MAGIC_2000 } 63 namebuf[nt*256+o] = 0 as u8 64 nt = nt + 1 65 } else { i = le } 66 } 67 } 68 if nt < 2 { return 0 - 98 } 69 let cmd: *u8 = namebuf 70 let argv: *i64 = sys_mmap(64) as *i64 71 let envp: *i64 = sys_mmap(16) as *i64 72 envp[0] = 0 73 let path: *u8 = sys_mmap(512) 74 var mode: i64 = 0 75 if cmd[0]==(114 as u8) { if cmd[1]==(117 as u8) { if cmd[2]==(110 as u8) { if cmd[3]==(0 as u8) { mode=1 } else { if cmd[3]==(105 as u8) { mode=2 } } } } } 76 if cmd[0]==(101 as u8) { if cmd[1]==(108 as u8) { if cmd[2]==(102 as u8) { mode=3 } } } 77 if mode==0 { return 0 - 97 } 78 if mode==3 { 79 var p: i64 = ap(path, 0, "./_offc/" as *u8) 80 p = ap(path, p, namebuf + 256) 81 p = ap(path, p, ".elf" as *u8) 82 path[p] = 0 as u8 83 argv[0] = path as i64 84 var ai: i64 = 1 85 var tt: i64 = 2 86 while tt < nt { argv[ai] = (namebuf + tt*256) as i64; ai=ai+1; tt=tt+1 } 87 argv[ai] = 0 88 } else { 89 let hp: *u8 = "./_offc/nx_sov_build_run.elf" 90 var p2: i64 = ap(path, 0, hp) 91 path[p2] = 0 as u8 92 argv[0] = path as i64 93 argv[1] = (namebuf + 256) as i64 94 if mode==2 { argv[2] = "--install" as i64; argv[3] = 0 } else { argv[2] = 0 } 95 } 96 let pid: i64 = sys_fork() 97 if pid == 0 { 98 sys_execve(path, argv, envp) 99 sys_exit(96) 100 return 96 101 } 102 if pid < 0 { return 0 - 95 } 103 let status: *i64 = sys_mmap(16) as *i64 104 sys_wait4(pid, status, 0) 105 return (status[0] >> 8) & 0xff } 106 107func main() -> i64 { 108 let lb: *u8 = sys_mmap(K_MAGIC_1024) 109 var bn: i64 = ap(lb, 0, "JOBRUNNER up epoch=" as *u8) 110 bn = apn(lb, bn, sys_now_realtime_sec()) 111 lb[bn] = 10 as u8 112 let lf0: i64 = sys_openat_append(JL, 0x1a4) 113 if lf0 >= 0 { sys_write(lf0, lb, bn+1); sys_close(lf0) } 114 let namebuf: *u8 = sys_mmap(K_MAGIC_2048) 115 var go: i64 = 1 116 while go == 1 { 117 let box: *i64 = sys_mmap(16) as *i64 118 let q: *u8 = sys_read_file(JQ, box) 119 if (q as i64) != 0 { 120 let n: i64 = box[0] 121 var done: i64 = jr_cursor() 122 var idx: i64 = 0 123 var ls: i64 = 0 124 var i: i64 = 0 125 while i <= n { 126 var eol: i64 = 0 127 if i==n { if i>ls { eol=1 } } else { if (q[i] as i64)==10 { eol=1 } } 128 if eol==1 { 129 if idx >= done { if i > ls { if (q[ls] as i64) != 35 { 130 let rc: i64 = jr_exec(q, ls, i, namebuf) 131 var o: i64 = ap(lb, 0, "JOBRUN idx=" as *u8) 132 o = apn(lb, o, idx) 133 o = ap(lb, o, " line=" as *u8) 134 var cpy: i64 = ls 135 while cpy < i { if o < 900 { lb[o]=q[cpy]; o=o+1 } cpy=cpy+1 } 136 o = ap(lb, o, " exit=" as *u8) 137 o = apn(lb, o, rc) 138 o = ap(lb, o, " epoch=" as *u8) 139 o = apn(lb, o, sys_now_realtime_sec()) 140 lb[o] = 10 as u8 141 let lf: i64 = sys_openat_append(JL, 0x1a4) 142 if lf >= 0 { sys_write(lf, lb, o+1); sys_close(lf) } 143 } } 144 done = idx + 1 145 jr_cursor_set(done) 146 } 147 idx = idx + 1 148 ls = i + 1 149 } 150 i = i + 1 151 } 152 } 153 sys_sleep_ms(K_MAGIC_2000) 154 } 155 return 0 156}