code wiki / _hdl_build / nx_lease.nx

nx_lease.nx source

↩ module page · 281 lines · 18110 B

1// nx_lease.nx -- THE SOVEREIGN LEASE PRIMITIVE (eats debt seq12/D002: "WMS write lane unlocked = 2// race debt; claims/lease it"). Advisory TTL leases for contended write lanes (ws_put / planes / 3// MEMORY-class shared state): ACQUIRE is atomic (mkdirat -- EEXIST = held), takeover of a stale or 4// released lease is CAS-VERIFIED (write own stamp via tmp+renameat, read back, own nonce wins -- 5// last-writer-wins + verify = the loser backs off), RELEASE flips the stamp to released and NEVER 6// unlinks or rmdirs (the never-unlink-lock law: lock dirs are additive; a released stamp is the 7// reusable slot). Self-mkdirs knowledge/lease (rule 20). Stamp = one line: 8// held|released<TAB>owner<TAB>epoch<TAB>ttl<TAB>nonce 9// Stale = state held AND now > epoch + ttl (the HOLDER's declared ttl -- crash-safe by construction: 10// a dead holder's lease self-expires; no daemon needed). 11// nx_lease acquire <name> <owner> <ttl-sec> exit 0 ACQUIRED | 3 BUSY (holder shown) | 4 io 12// nx_lease release <name> <owner> exit 0 RELEASED | 3 REFUSED not-holder | 4 io 13// nx_lease check <name> exit 0 prints stamp | 1 free 14// nx_lease selftest 7 teeth, verdict=GREEN/RED, exit 0/5 15// name grammar [a-zA-Z0-9_-] only (deny slash/dot/traversal by construction). 16// expect_exit: 0 license_tier: ORIGINAL No hw writes (Rule 26). 17import "nx_lease_lib.nx" // the primitive itself; this file is the CLI verbs + selftest (2026-09-03 extraction) 18 19// 2026-09-05: the check verb's second and third roots were INLINE LITERALS assigned inside a nested loop, and the 20// compiled probe never opened them -- LS-FREE against a stamp the shell tool could read at that very path, from the 21// same CWD. The first root is a named const and worked. So: the roots are consts, the probe is ONE function that 22// main and the selftest both call, and the selftest plants a HELD stamp under the buildroot root and requires the 23// probe to find it THERE (the old selftest was GREEN because every fixture lived under the first root). 24const LS_ROOT_BUILDROOT: *u8 = "buildroot/knowledge/lease/" 25const LS_ROOT_PARENT: *u8 = "../knowledge/lease/" 26const LS_ROOTS: i64 = 3 27func ls_root_at(ri: i64) -> *u8 { 28 if ri == 1 { return LS_ROOT_BUILDROOT } 29 if ri == 2 { return LS_ROOT_PARENT } 30 return LS_DEFAULT_ROOT 31} 32// probes every root for <name>'s stamp: a HELD stamp (h) from any root wins, else the first stamp found. 33// returns the stamp length copied into rb (0 when no root holds one) and writes the winning root index to rsel[0]. 34func ls_probe_roots(name: *u8, rb: *u8, rsel: *i64) -> i64 { 35 let dir: *u8 = sys_mmap(LS_PATHCAP) 36 let sp: *u8 = sys_mmap(LS_PATHCAP) 37 let tb: *u8 = sys_mmap(LS_STAMPCAP) 38 var rn: i64 = 0 39 rsel[0] = 0 - 1 40 var ri: i64 = 0 41 var chosen: i64 = 0 42 while ri < LS_ROOTS { 43 if chosen == 0 { 44 let root: *u8 = ls_root_at(ri) 45 ls_dirpath_root(root, name, dir) 46 ls_stamp_path(dir, sp) 47 let tn: i64 = ls_read(sp, tb, LS_STAMPCAP - 1) 48 if tn > 0 { 49 var take: i64 = 0 50 if rn <= 0 { take = 1 } 51 if tb[0] == (104 as u8) { take = 1; chosen = 1 } 52 if take == 1 { 53 rn = tn 54 rsel[0] = ri 55 var ci: i64 = 0 56 while ci < tn { rb[ci] = tb[ci]; ci = ci + 1 } 57 } 58 } 59 } 60 ri = ri + 1 61 } 62 return rn 63} 64func main(argc: i64, argv: *i64) -> i64 { 65 if argc < 2 { ls_werr("usage: nx_lease {acquire <name> <owner> <ttl-sec> | release <name> <owner> | check <name> | selftest}\n" as *u8); sys_exit(LS_EXIT_USAGE); return LS_EXIT_USAGE } 66 let v: *u8 = argv[1] as *u8 67 let hb: *u8 = sys_mmap(LS_PATHCAP) 68 69 if v[0] == (LS_V_S as u8) { 70 var pass: i64 = 1 71 if ls_name_ok("../evil" as *u8) == 1 { pass = 0 } 72 if ls_name_ok("a/b" as *u8) == 1 { pass = 0 } 73 if ls_name_ok("wms-write" as *u8) == 0 { pass = 0 } 74 if ls_acquire("lease_probe" as *u8, "tester-a" as *u8, LS_MAGIC_3600, hb) != 0 { pass = 0; ls_werr("t1 acquire fail\n" as *u8) } 75 if ls_acquire("lease_probe" as *u8, "tester-b" as *u8, LS_MAGIC_3600, hb) != 1 { pass = 0; ls_werr("t2 busy-expected fail\n" as *u8) } 76 if ls_release("lease_probe" as *u8, "tester-b" as *u8) != 1 { pass = 0; ls_werr("t3 wrong-owner-release fail\n" as *u8) } 77 if ls_release("lease_probe" as *u8, "tester-a" as *u8) != 0 { pass = 0; ls_werr("t4 release fail\n" as *u8) } 78 if ls_acquire("lease_probe" as *u8, "tester-b" as *u8, LS_MAGIC_3600, hb) != 0 { pass = 0; ls_werr("t5 reacquire-after-release fail\n" as *u8) } 79 if ls_release("lease_probe" as *u8, "tester-b" as *u8) != 0 { pass = 0; ls_werr("t6 cleanup fail\n" as *u8) } 80 if ls_acquire("lease_probe2" as *u8, "tester-a" as *u8, 0, hb) != 0 { pass = 0; ls_werr("t7a stale-setup fail\n" as *u8) } 81 if ls_acquire("lease_probe2" as *u8, "tester-b" as *u8, LS_MAGIC_3600, hb) != 0 { pass = 0; ls_werr("t7b stale-takeover fail\n" as *u8) } 82 if ls_release("lease_probe2" as *u8, "tester-b" as *u8) != 0 { pass = 0; ls_werr("t7c cleanup fail\n" as *u8) } 83 // ---- TOOTH 8: CONCURRENCY -- THE ONLY PROPERTY THAT MAKES THIS A MUTEX, AND UNTIL 2026-08-08 84 // THE ONE PROPERTY NEVER TESTED. Teeth 1-7 are all SEQUENTIAL acquires in ONE process, and the 85 // source contained zero sys_fork/sys_clone/sys_wait, so mutual exclusion under SIMULTANEOUS 86 // acquire had never been exercised in either direction and a GREEN said nothing about it. 87 // ★A MUTEX WHOSE SELFTEST NEVER RUNS TWO ACQUIRERS AT ONCE IS UNTESTED FOR THE ONLY PROPERTY 88 // THAT MAKES IT A MUTEX; A GREEN FROM A SEQUENTIAL FIXTURE IS SILENT ABOUT EVERY CONCURRENT PATH. 89 // WHY NOW: two independently forked sweeps were OBSERVED both reporting acquisition of one slot. 90 // The observation is real; the cause is NOT reproduced. This tooth is the experiment that 91 // decides it -- it does not assume the answer. 92 // ★REPEATED ROUNDS ON PURPOSE: a race that fires 1-in-K is invisible in a single trial. 93 var rround: i64 = 0 94 while rround < 5 { 95 // ★UNIQUE NAME PER RUN, NOT JUST PER ROUND -- MY FIRST FIXTURE CONTAMINATED ITSELF. 96 // v1 used fixed literals lease_race0..4 and RELEASED them at the end of each round. On the 97 // SECOND run of the selftest those names still carried a `released` stamp, so every racer 98 // took the RELEASED-TAKEOVER path (g_st==2) instead of the stampless path, and all four 99 // legitimately claimed. The failure count jumped 3/5 -> 5/5 and looked exactly like a 100 // REGRESSION FROM MY FIX, when it was leftover state from the previous run. 101 // ★★A FIXTURE THAT PERSISTS STATE BETWEEN RUNS STOPS MEASURING THE CODE AND STARTS MEASURING 102 // ITS OWN HISTORY -- and the false signal it produces points at whatever you changed last. 103 // pid+round makes every round of every run a name that has never existed before. 104 let rnb: *u8 = sys_mmap(LS_PATHCAP) 105 var rno: i64 = ls_cat(rnb, 0, "lrace" as *u8) 106 rno = ls_catn(rnb, rno, ls_pid()) 107 rnb[rno] = 95 as u8 108 rno = rno + 1 109 rno = ls_catn(rnb, rno, rround) 110 rnb[rno] = 0 as u8 111 let rname: *u8 = rnb 112 var kid: i64 = 0 113 while kid < 4 { 114 var kown: *u8 = "ra" as *u8 115 if kid == 1 { kown = "rb" as *u8 } 116 if kid == 2 { kown = "rc" as *u8 } 117 if kid == 3 { kown = "rd" as *u8 } 118 let kpid: i64 = sys_fork() 119 if kpid == 0 { 120 let khb: *u8 = sys_mmap(LS_PATHCAP) 121 let kr: i64 = ls_acquire(rname, kown, LS_MAGIC_3600, khb) 122 if kr == 0 { sys_exit(0) } 123 sys_exit(1) 124 } 125 kid = kid + 1 126 } 127 var got: i64 = 0 128 var w: i64 = 0 129 while w < 4 { 130 let stp: *i64 = sys_mmap(16) as *i64 131 sys_wait4(0 - 1, stp, 0) 132 if ((stp[0] >> 8) % 256) == 0 { got = got + 1 } 133 w = w + 1 134 } 135 // ★ASSERT EXACTLY ONE. got>1 = not mutually exclusive (the defect this hunts). 136 // got==0 = nobody won, which is ALSO a failure and must not read as "safe". 137 if got != 1 { 138 pass = 0 139 ls_werr("t8 RACE FAIL: acquirers=" as *u8); ls_wn(got); ls_werr(" expected exactly 1\n" as *u8) 140 } 141 ls_release(rname, "ra" as *u8) 142 ls_release(rname, "rb" as *u8) 143 ls_release(rname, "rc" as *u8) 144 ls_release(rname, "rd" as *u8) 145 rround = rround + 1 146 } 147 // ---- TOOTH 9: TAKEOVER CONCURRENCY. Tooth 8 races on FRESH names, so every racer there goes 148 // through the INITIAL claim; the TAKEOVER path (a stamp that EXISTS and has been judged 149 // released/expired) is never reached, and a GREEN tooth 8 is SILENT about it. 150 // ★★★★★★A CONCURRENCY TEST COVERS ONLY THE CODE PATH ITS FIXTURE HAPPENS TO REACH -- "THE MUTEX IS 151 // PROVEN" IS A CLAIM ABOUT THE FIXTURE, NOT ABOUT THE MUTEX. This path is the one a real sweep 152 // uses constantly (release the lease, next sweep takes it over), so it is the COMMON case, not 153 // an exotic one -- and it is the case my contaminated tooth-8 fixture reached BY ACCIDENT, where 154 // it showed acquirers=4. 155 var tround: i64 = 0 156 while tround < 5 { 157 let tnb: *u8 = sys_mmap(LS_PATHCAP) 158 var tno: i64 = ls_cat(tnb, 0, "ltake" as *u8) 159 tno = ls_catn(tnb, tno, ls_pid()) 160 tnb[tno] = 95 as u8 161 tno = tno + 1 162 tno = ls_catn(tnb, tno, tround) 163 tnb[tno] = 0 as u8 164 let tname: *u8 = tnb 165 // ★ASSERT THE FIXTURE REACHED THE CONDITION BEFORE ASSERTING THE OUTCOME. If this seed 166 // acquire+release does not leave a RELEASED stamp, the racers below take the INITIAL path 167 // and tooth 9 silently degrades into a second copy of tooth 8 -- passing while testing 168 // nothing new. That is the vacuous-fixture failure, so it is checked, not assumed. 169 if ls_acquire(tname, "seed" as *u8, LS_MAGIC_3600, hb) != 0 { pass = 0; ls_werr("t9 seed-acquire fail (FIXTURE DID NOT REACH THE CONDITION)\n" as *u8) } 170 if ls_release(tname, "seed" as *u8) != 0 { pass = 0; ls_werr("t9 seed-release fail (FIXTURE DID NOT REACH THE CONDITION)\n" as *u8) } 171 var tkid: i64 = 0 172 while tkid < 4 { 173 var town: *u8 = "ta" as *u8 174 if tkid == 1 { town = "tb" as *u8 } 175 if tkid == 2 { town = "tc" as *u8 } 176 if tkid == 3 { town = "td" as *u8 } 177 let tpid: i64 = sys_fork() 178 if tpid == 0 { 179 let thb: *u8 = sys_mmap(LS_PATHCAP) 180 let tr: i64 = ls_acquire(tname, town, LS_MAGIC_3600, thb) 181 if tr == 0 { sys_exit(0) } 182 sys_exit(1) 183 } 184 tkid = tkid + 1 185 } 186 var tgot: i64 = 0 187 var tw: i64 = 0 188 while tw < 4 { 189 let tstp: *i64 = sys_mmap(16) as *i64 190 sys_wait4(0 - 1, tstp, 0) 191 if ((tstp[0] >> 8) % 256) == 0 { tgot = tgot + 1 } 192 tw = tw + 1 193 } 194 // tgot>1 = the takeover ABA. tgot==0 = a released lease nobody could reclaim, which is a 195 // DIFFERENT and equally real defect (a permanently wedged slot) and must not read as safe. 196 if tgot != 1 { 197 pass = 0 198 ls_werr("t9 TAKEOVER-RACE FAIL: acquirers=" as *u8); ls_wn(tgot); ls_werr(" expected exactly 1 -- KNOWN-OPEN, OWNED, REPRODUCED: debt 1786244397. This RED is not a new breakage and not noise: teeth 1-8 (incl. fresh-name concurrency) are GREEN and the initial/stampless claim is correct by construction. Remedy is renameat2(RENAME_NOREPLACE) to move the dead stamp aside -- arbitration by WHO MOVED IT, which needs no unique nonce (the current one collides within a process-second). DO NOT green-wash this tooth; deleting it hides the only reproduction we have.\n" as *u8) 199 } 200 ls_release(tname, "ta" as *u8) 201 ls_release(tname, "tb" as *u8) 202 ls_release(tname, "tc" as *u8) 203 ls_release(tname, "td" as *u8) 204 tround = tround + 1 205 } 206 // 2026-09-05 CROSS-ROOT PROBE TOOTH: the check verb's second root was an inline literal that never opened, and this 207 // selftest read GREEN because every fixture lived under the first root -- a fixture the defect could not fail. Plant a 208 // HELD stamp under the buildroot root and require the probe to find it THERE and read it as held; then require a 209 // name held nowhere to read absent (neg-control), so a probe that answered present for everything cannot pass. 210 let xnb: *u8 = sys_mmap(LS_PATHCAP) 211 var xno: i64 = ls_cat(xnb, 0, "lsxroot" as *u8) 212 xno = ls_catn(xnb, xno, ls_pid()) 213 xnb[xno] = 0 as u8 214 let xhb: *u8 = sys_mmap(LS_PATHCAP) 215 let xr: i64 = ls_acquire_root(LS_ROOT_BUILDROOT, xnb, "xroot" as *u8, LS_MAGIC_3600, xhb) 216 let xrb: *u8 = sys_mmap(LS_STAMPCAP) 217 let xsel: *i64 = sys_mmap(LS_STAMPCAP) as *i64 218 let xrn: i64 = ls_probe_roots(xnb, xrb, xsel) 219 ls_werr("LS-SELFTEST cross-root: acquire_rc=" as *u8); ls_wn(xr); ls_werr(" probe_len=" as *u8); ls_wn(xrn); ls_werr(" root_index=" as *u8); ls_wn(xsel[0]); ls_werr("\n" as *u8) 220 if xr != 0 { pass = 0; ls_werr("LS-SELFTEST FAIL cross-root fixture did not acquire under the buildroot root\n" as *u8) } 221 if xrn <= 0 { pass = 0; ls_werr("LS-SELFTEST FAIL cross-root probe found NO stamp for a lease held under the buildroot root\n" as *u8) } 222 if xsel[0] != 1 { pass = 0; ls_werr("LS-SELFTEST FAIL cross-root probe found the stamp under the wrong root\n" as *u8) } 223 if xrn > 0 { if xrb[0] != (104 as u8) { pass = 0; ls_werr("LS-SELFTEST FAIL cross-root stamp was not read as HELD\n" as *u8) } } 224 ls_release_root(LS_ROOT_BUILDROOT, xnb, "xroot" as *u8) 225 xnb[xno] = 122 as u8 226 xnb[xno + 1] = 0 as u8 227 let xrn2: i64 = ls_probe_roots(xnb, xrb, xsel) 228 if xrn2 > 0 { pass = 0; ls_werr("LS-SELFTEST FAIL neg-control: a name held nowhere read as present\n" as *u8) } 229 if pass == 1 { ls_werr("LS-SELFTEST OK verdict=GREEN teeth=11 (concurrency: fresh-name AND released-takeover, 5 rounds x 4 racers each; cross-root probe + neg-control)\n" as *u8); sys_exit(0); return 0 } 230 ls_werr("LS-SELFTEST FAIL verdict=RED\n" as *u8) 231 sys_exit(LS_EXIT_SELF) 232 return LS_EXIT_SELF 233 } 234 235 if argc < 3 { ls_werr("verb needs <name>\n" as *u8); sys_exit(LS_EXIT_USAGE); return LS_EXIT_USAGE } 236 let name: *u8 = argv[2] as *u8 237 if ls_name_ok(name) == 0 { ls_werr("LS-REFUSED bad name (grammar [a-zA-Z0-9_-])\n" as *u8); sys_exit(LS_EXIT_USAGE); return LS_EXIT_USAGE } 238 239 if v[0] == (LS_V_A as u8) { 240 if argc < 5 { ls_werr("acquire needs <name> <owner> <ttl-sec>\n" as *u8); sys_exit(LS_EXIT_USAGE); return LS_EXIT_USAGE } 241 let owner: *u8 = argv[3] as *u8 242 var ttl: i64 = 0 243 let ts: *u8 = argv[4] as *u8 244 var ti: i64 = 0 245 while ts[ti] != (0 as u8) { let c: i64 = ts[ti]; if c >= LS_D0 { if c <= LS_D9 { ttl = ttl * LS_B10 + (c - LS_D0) } } ti = ti + 1 } 246 let r: i64 = ls_acquire(name, owner, ttl, hb) 247 if r == 0 { ls_werr("LS-ACQUIRED " as *u8); ls_werr(name); ls_werr(" owner=" as *u8); ls_werr(owner); ls_werr(" ttl=" as *u8); ls_wn(ttl); ls_werr("\n" as *u8); sys_exit(0); return 0 } 248 if r == 1 { ls_werr("LS-BUSY " as *u8); ls_werr(name); ls_werr(" holder=" as *u8); ls_werr(hb); ls_werr("\n" as *u8); sys_exit(LS_EXIT_BUSY); return LS_EXIT_BUSY } 249 ls_werr("LS-FAIL io\n" as *u8) 250 sys_exit(LS_EXIT_IO) 251 return LS_EXIT_IO 252 } 253 if v[0] == (LS_V_R as u8) { 254 if argc < 4 { ls_werr("release needs <name> <owner>\n" as *u8); sys_exit(LS_EXIT_USAGE); return LS_EXIT_USAGE } 255 let owner2: *u8 = argv[3] as *u8 256 let r2: i64 = ls_release(name, owner2) 257 if r2 == 0 { ls_werr("LS-RELEASED " as *u8); ls_werr(name); ls_werr("\n" as *u8); sys_exit(0); return 0 } 258 if r2 == 1 { ls_werr("LS-REFUSED not-holder (or not held)\n" as *u8); sys_exit(LS_EXIT_BUSY); return LS_EXIT_BUSY } 259 ls_werr("LS-FAIL io\n" as *u8) 260 sys_exit(LS_EXIT_IO) 261 return LS_EXIT_IO 262 } 263 if v[0] == (LS_V_C as u8) { 264 // TWO LEASE STORES UNDER ONE NAME, MEASURED 2026-09-05: the lease dir is CWD-relative, so a check 265 // from the serving root printed LS-FREE while nishi_compare_regen (CWD=buildroot) held the lease and 266 // refused LS-BUSY seconds later. A false FREE is the worst answer a mutex probe can give, so the 267 // READ side now probes every root the estate's two CWDs produce and a HELD stamp from any root wins; 268 // the WRITE side (acquire and release) is deliberately unchanged -- moving writers is a separate decision. 269 let rb: *u8 = sys_mmap(LS_STAMPCAP) 270 let rsel: *i64 = sys_mmap(LS_STAMPCAP) as *i64 271 let rn: i64 = ls_probe_roots(name, rb, rsel) 272 if rn > 0 { ls_werr("LS-ROOT " as *u8); ls_werr(ls_root_at(rsel[0])); ls_werr(" (3 roots probed, a held stamp from any root wins)" as *u8); ls_werr("\n" as *u8) } 273 if rn <= 0 { ls_werr("LS-FREE " as *u8); ls_werr(name); ls_werr("\n" as *u8); sys_exit(1); return 1 } 274 sys_write(1, rb, rn) 275 sys_exit(0) 276 return 0 277 } 278 ls_werr("usage: nx_lease {acquire|release|check|selftest}\n" as *u8) 279 sys_exit(LS_EXIT_USAGE) 280 return LS_EXIT_USAGE 281}