nx_ioae_confread_v2_20260907.nx source
↩ module page · 118 lines · 6051 B
1// TEST ONLY actual heavyio config reader; allocation seams count real 64KiB mappings.
2import "nx_ioae_lib_test_20260907.nx"
3const HIO_CONF: *u8 = "knowledge/heavyio.conf"
4const HIO_ADMIT: i64 = 1
5const HIO_DEFER: i64 = 0
6const HIO_UNOBSERVABLE: i64 = 0 - 1
7const HIO_MAXP: i64 = 32 // producer rows the conf may carry; the reader announces when it fills
8const HIO_NAMEW: i64 = 64 // one producer needle slot (comm names are 15 bytes; cmdline needles longer)
9const HIO_CONFCAP: i64 = 65536
10const HIO_SPACE: i64 = 32
11const HIO_NL: i64 = 10
12const HIO_HASH: i64 = 35
13// cfg[] layout (i64 slots)
14const HIO_C_NPROD: i64 = 0
15const HIO_C_SLOTS: i64 = 1
16const HIO_C_FLOOR: i64 = 2
17const HIO_C_MAXC: i64 = 3
18const HIO_C_WMIN: i64 = 4
19const HIO_C_WMAX: i64 = 5
20const HIO_C_FILLED: i64 = 6 // 1 when HIO_MAXP was reached (rows beyond it were NOT read -- announced)
21const HIO_C_TTL: i64 = 7 // slot_ttl <sec>: crash guard for a HUNG-BUT-ALIVE holder (a dead one frees at once)
22const HIO_C_SLOTS_N: i64 = 8
23const HIO_C_BYTES: i64 = 64 // HIO_C_SLOTS_N * 8
24// out[] layout for hio_admit: 0 running 1 width 2 storm_budget 3 slot (-1 none). Adopters allocate HIO_C_BYTES (64),
25// which covers all four; HIO_OUT_BYTES names the minimum for new callers.
26const HIO_O_RUNNING: i64 = 0
27const HIO_O_WIDTH: i64 = 1
28const HIO_O_STORM: i64 = 2
29const HIO_O_SLOT: i64 = 3
30const HIO_OUT_BYTES: i64 = 32
31// THE POOL ROOT IS RESOLVED, NEVER ASSUMED (measured 2026-09-03: nx_compare_regen chdirs to buildroot, where
32// knowledge/heavyio.conf is ABSENT, so its admission read UNOBSERVABLE and it ran unbounded while the census said
33// ADOPTED). Probe the conf at knowledge/ then ../knowledge/; the lease dir follows the SAME root, so every CWD
34// shares ONE pool. hio_root returns 1 = knowledge/ 2 = ../knowledge/ 0 = neither (UNOBSERVABLE).
35const HIO_ROOT_A: *u8 = "knowledge/"
36const HIO_ROOT_B: *u8 = "../knowledge/"
37const HIO_CONF_LEAF: *u8 = "heavyio.conf"
38const HIO_LEASE_LEAF: *u8 = "lease/"
39const HIO_SLOT_PFX: *u8 = "heavyio-slot-"
40const HIO_OWNER_PFX: *u8 = "pid"
41const HIO_PROC_PFX: *u8 = "/proc/"
42const HIO_PROC_LEAF: *u8 = "/stat"
43const HIO_PATHCAP: i64 = 256
44const HIO_TTL_DEFAULT: i64 = 900 // used ONLY when the conf carries no slot_ttl row; the conf explains 900
45const HIO_POOL_NONE: i64 = 0 - 1 // every slot held by a LIVE holder -> DEFER
46const HIO_POOL_IO: i64 = 0 - 2 // every slot attempt failed with io (lease root unwritable) -> UNOBSERVABLE, never a stall
47
48static efg_conf_live: i64
49static efg_conf_allocs: i64
50static efg_conf_frees: i64
51static efg_conf_errors: i64
52func hio_conf_buffer_alloc() -> *u8 {
53 if efg_conf_live != 0 { efg_conf_errors = 1 }
54 let p: *u8 = sys_mmap(HIO_CONFCAP)
55 efg_conf_live = p as i64; efg_conf_allocs = efg_conf_allocs+1; return p
56}
57func hio_conf_buffer_free(p: *u8) -> i64 {
58 if efg_conf_live != (p as i64) { efg_conf_errors = 1 }
59 efg_conf_live = 0; efg_conf_frees = efg_conf_frees+1
60 let rc: i64 = sys_munmap(p,HIO_CONFCAP)
61 if rc != 0 { efg_conf_errors = 1 }; return rc
62}
63func hio_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
64func hio_eol(q: *u8, i: i64, n: i64) -> i64 { var e: i64 = i; var s: i64 = 1; while s == 1 { if e >= n { s = 0 } else { if q[e] == (HIO_NL as u8) { s = 0 } else { e = e + 1 } } } return e }
65func hio_keyis(q: *u8, s: i64, e: i64, key: *u8) -> i64 {
66 var i: i64 = 0
67 while key[i] != (0 as u8) { if s + i >= e { return 0 } if q[s + i] != key[i] { return 0 } i = i + 1 }
68 if s + i >= e { return 0 }
69 if q[s + i] != (HIO_SPACE as u8) { return 0 }
70 return 1
71}
72func hio_atoi(q: *u8, s: i64, e: i64) -> i64 {
73 var v: i64 = 0; var i: i64 = s; var seen: i64 = 0
74 while i < e { let c: i64 = q[i] as i64; if c >= 48 { if c <= 57 { v = v * 10 + (c - 48); seen = 1; i = i + 1 } else { i = e } } else { i = e } }
75 if seen == 0 { return 0 - 1 }
76 return v
77}
78func hio_slot(names: *u8, i: i64) -> *u8 { return ((names as i64) + i * HIO_NAMEW) as *u8 }
79func hio_conf_read(path: *u8, cfg: *i64, names: *u8) -> i64 {
80 var k: i64 = 0
81 while k < HIO_C_SLOTS_N { cfg[k] = 0 - 1; k = k + 1 }
82 cfg[HIO_C_NPROD] = 0
83 cfg[HIO_C_FILLED] = 0
84 let fd: i64 = sys_openat_rd(path)
85 if fd < 0 { return 0 }
86 let buf: *u8 = hio_conf_buffer_alloc()
87 var n: i64 = 0
88 var go: i64 = 1
89 while go == 1 { let r: i64 = sys_read(fd, ((buf as i64) + n) as *u8, HIO_CONFCAP - n); if r <= 0 { go = 0 } else { n = n + r } if n >= HIO_CONFCAP { go = 0 } }
90 sys_close(fd)
91 if n <= 0 { hio_conf_buffer_free(buf); return 0 }
92 var i: i64 = 0
93 while i < n {
94 let le: i64 = hio_eol(buf, i, n)
95 if le > i { if (buf[i] as i64) != HIO_HASH {
96 if hio_keyis(buf, i, le, "producer" as *u8) == 1 {
97 let np: i64 = cfg[HIO_C_NPROD]
98 if np < HIO_MAXP {
99 let d: *u8 = hio_slot(names, np)
100 var p: i64 = i + 9
101 var w: i64 = 0
102 while p < le { if buf[p] == (HIO_SPACE as u8) { p = le } else { if w < HIO_NAMEW - 1 { d[w] = buf[p]; w = w + 1 } p = p + 1 } }
103 d[w] = 0 as u8
104 if w > 0 { cfg[HIO_C_NPROD] = np + 1 }
105 } else { cfg[HIO_C_FILLED] = 1 }
106 }
107 if hio_keyis(buf, i, le, "slots_per_cpu" as *u8) == 1 { cfg[HIO_C_SLOTS] = hio_atoi(buf, i + 14, le) }
108 if hio_keyis(buf, i, le, "floor" as *u8) == 1 { cfg[HIO_C_FLOOR] = hio_atoi(buf, i + 6, le) }
109 if hio_keyis(buf, i, le, "max_centi" as *u8) == 1 { cfg[HIO_C_MAXC] = hio_atoi(buf, i + 10, le) }
110 if hio_keyis(buf, i, le, "wmin" as *u8) == 1 { cfg[HIO_C_WMIN] = hio_atoi(buf, i + 5, le) }
111 if hio_keyis(buf, i, le, "wmax" as *u8) == 1 { cfg[HIO_C_WMAX] = hio_atoi(buf, i + 5, le) }
112 if hio_keyis(buf, i, le, "slot_ttl" as *u8) == 1 { cfg[HIO_C_TTL] = hio_atoi(buf, i + 9, le) }
113 } }
114 i = le + 1
115 }
116 hio_conf_buffer_free(buf)
117 return 1
118}