code wiki / _hdl_build / nx_lease.nx
nx_lease.nx
buildroot/runtime/_hdl_build/nx_lease.nx
about
nx_lease.nx -- THE SOVEREIGN LEASE PRIMITIVE (eats debt seq12/D002: "WMS write lane unlocked =
race debt; claims/lease it"). Advisory TTL leases for contended write lanes (ws_put / planes /
MEMORY-class shared state): ACQUIRE is atomic (mkdirat -- EEXIST = held), takeover of a stale or
released lease is CAS-VERIFIED (write own stamp via tmp+renameat, read back, own nonce wins --
last-writer-wins + verify = the loser backs off), RELEASE flips the stamp to released and NEVER
unlinks or rmdirs (the never-unlink-lock law: lock dirs are additive; a released stamp is the
reusable slot). Self-mkdirs knowledge/lease (rule 20). Stamp = one line:
held|released<TAB>owner<TAB>epoch<TAB>ttl<TAB>nonce
Stale = state held AND now > epoch + ttl (the HOLDER's declared ttl -- crash-safe by construction:
a dead holder's lease self-expires; no daemon needed).
nx_lease acquire <name> <owner> <ttl-sec> exit 0 ACQUIRED | 3 BUSY (holder shown) | 4 io
nx_lease release <name> <owner> exit 0 RELEASED | 3 REFUSED not-holder | 4 io
nx_lease check <name> exit 0 prints stamp | 1 free
nx_lease selftest 7 teeth, verdict=GREEN/RED, exit 0/5
name grammar [a-zA-Z0-9_-] only (deny slash/dot/traversal by construction).
expect_exit: 0 license_tier: ORIGINAL No hw writes (Rule 26).
dependencies 1 imports · 2 importers
imports: nx_syscalls.nx
imported by: nx_arbiter_gate.nxnx_gate_mutation_sweep.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 18 | const LS_MAGIC_3600: i64 = 3600 |
| 20 | const LS_STDERR: i64 = 2 |
| 21 | const LS_PATHCAP: i64 = 256 |
| 22 | const LS_STAMPCAP: i64 = 512 |
| 23 | const LS_MODE: i64 = 0x1a4 |
| 24 | const LS_DMODE: i64 = 0x1ed |
| 25 | const LS_MKDIRAT: i64 = 258 |
| 26 | const LS_ATFDCWD: i64 = 0 - 100 |
| 27 | const LS_GETPID: i64 = 172 |
| 28 | const LS_TAB: i64 = 9 |
| 29 | const LS_NL: i64 = 10 |
| 30 | const LS_D0: i64 = 48 |
| 31 | const LS_D9: i64 = 57 |
| 32 | const LS_B10: i64 = 10 |
| 33 | const LS_NUMB: i64 = 24 |
| 34 | const LS_EXIT_USAGE: i64 = 2 |
| 35 | const LS_EXIT_BUSY: i64 = 3 |
| 36 | const LS_EXIT_IO: i64 = 4 |
| 37 | const LS_EXIT_SELF: i64 = 5 |
| 38 | const LS_V_A: i64 = 97 |
| 39 | const LS_V_R: i64 = 114 |
| 40 | const LS_V_C: i64 = 99 |
| 41 | const LS_V_S: i64 = 115 |
| 42 | const LS_NONCE_MOD: i64 = 1000000 |
functions
| 44 | func ls_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } called by 1: ls_werr |
| 45 | func ls_werr(s: *u8) -> i64 { sys_write(LS_STDERR, s, ls_slen(s)); return 0 } |
| 46 | func ls_wn(v: i64) -> i64 |
| 59 | func ls_cat(d: *u8, off: i64, s: *u8) -> i64 |
| 65 | func ls_catn(d: *u8, off: i64, v: i64) -> i64 |
| 77 | func ls_eq(a: *u8, b: *u8) -> i64 called by 1: ls_release |
| 84 | func ls_name_ok(s: *u8) -> i64 called by 1: main |
| 100 | func ls_mkdir(p: *u8) -> i64 { return __syscall(LS_MKDIRAT, LS_ATFDCWD, p as i64, LS_DMODE, 0, 0, 0) } called by 1: ls_acquire |
| 101 | func ls_dirpath(name: *u8, out: *u8) -> i64 |
| 108 | func ls_read(path: *u8, buf: *u8, cap: i64) -> i64 |
| 128 | func ls_parse2(buf: *u8, n: i64, ob: *u8, obcap: i64) -> i64 |
| 160 | func ls_claim(dir: *u8, owner: *u8, ttl: i64, nonce: i64) -> i64 |
| 199 | func ls_stamp_path(dir: *u8, out: *u8) -> i64 |
| 206 | func ls_unclaim(dir: *u8, owner: *u8, nonce: i64) -> i64 called by 1: ls_release calls 9: sys_mmapls_stamp_pathls_catls_catnsys_now_realtime_secsys_openat_wr+3 |
| 237 | func ls_pid() -> i64 { return __syscall(LS_GETPID, 0, 0, 0, 0, 0, 0) } |
| 239 | func ls_acquire(name: *u8, owner: *u8, ttl: i64, hb: *u8) -> i64 |
| 280 | func ls_release(name: *u8, owner: *u8) -> i64 |
| 297 | func main(argc: i64, argv: *i64) -> i64 |