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}