feat(v4): the kernel keeps a registry of nodes and checks who may ask (MESH.md 9a.4)
Any node may birth and wire its own; only Hera sleeps, wakes and kills, by number. Requests have fixed numbers, -6 to -18. NODE-BORN takes the number; NODE-KILL a number. test_manage.c: 41 checks at both widths. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
bf97f339f6
commit
d154342314
+116
-49
@@ -1,4 +1,4 @@
|
||||
/* manage.c -- what Hera asks of whoever holds the fabric. See manage.h.
|
||||
/* manage.c -- what a node asks of whoever holds the fabric. See manage.h.
|
||||
*
|
||||
* Nothing here uses the C library: the bare-metal kernel links this file.
|
||||
*/
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
const char *const v4_manage_words[V4_MANAGE_WORDS] = {
|
||||
"NODE-ME", "NODE-BORN", "NODE-WIRE", "NODE-UNWIRE", "NODE-SLEEP", "NODE-WAKE", "NODE-KILL", "NODE-PARITY",
|
||||
"CAPSULE-OPEN", "CAPSULE-CELL", "CAPSULE-LINE"
|
||||
"CAPSULE-OPEN", "CAPSULE-CELL", "CAPSULE-LINE", "NODE-CHILD", "NODE-PLACE"
|
||||
};
|
||||
|
||||
/* A character of the node's memory: four to a cell, the first lowest, as
|
||||
* the nucleus keeps text (capsules/v4/sys/core.f18). */
|
||||
* the system keeps text (capsules/v4/sys/core.f18). */
|
||||
static int in_memory(v4_cell baddr) { return baddr >= 0 && (baddr >> 2) < (v4_cell)V4_NODE_WORDS; }
|
||||
static char char_at(const v4_node *n, v4_cell baddr)
|
||||
{
|
||||
@@ -26,82 +26,149 @@ static void char_put(v4_node *n, v4_cell baddr, char c)
|
||||
|
||||
static unsigned place_of(v4_cell x) { return x < 0 ? ~0u : (unsigned)x; }
|
||||
|
||||
int v4_manage_serve(const v4_manage *m, unsigned place, unsigned request)
|
||||
static v4_manage_entry *by_number(const v4_manage *m, v4_cell number)
|
||||
{
|
||||
v4_fabric_node *asker = v4_fabric_node_at(m->f, place);
|
||||
unsigned k;
|
||||
if (number < 1) return 0;
|
||||
for (k = 0; k < m->reg_cap; k++) if (m->reg[k].number == number) return &m->reg[k];
|
||||
return 0;
|
||||
}
|
||||
static v4_manage_entry *by_place(const v4_manage *m, unsigned place)
|
||||
{
|
||||
unsigned k;
|
||||
for (k = 0; k < m->reg_cap; k++) if (m->reg[k].number != 0 && m->reg[k].place == place) return &m->reg[k];
|
||||
return 0;
|
||||
}
|
||||
/* the place is the asker's own, or that of a node it birthed */
|
||||
static int mine(const v4_manage *m, const v4_manage_entry *asker, unsigned place)
|
||||
{
|
||||
const v4_manage_entry *e = by_place(m, place);
|
||||
return asker && e && (e == asker || e->parent == asker->number);
|
||||
}
|
||||
/* error 12 on the node that asked: a store to NODE-ERROR raises it (D-18) */
|
||||
static int refuse(v4_node *n) { v4_node_store(n, n->error_reg, 12); return 1; }
|
||||
|
||||
int v4_manage_enter(const v4_manage *m, v4_cell number, unsigned place, v4_cell parent)
|
||||
{
|
||||
unsigned k;
|
||||
if (number < 1 || by_number(m, number)) return 0;
|
||||
for (k = 0; k < m->reg_cap; k++) {
|
||||
if (m->reg[k].number == 0) {
|
||||
m->reg[k].number = number; m->reg[k].parent = parent; m->reg[k].place = place;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int v4_manage_serve(const v4_manage *m, unsigned place, v4_cell request)
|
||||
{
|
||||
v4_fabric_node *at = v4_fabric_node_at(m->f, place);
|
||||
v4_manage_entry *me, *e;
|
||||
v4_node *n;
|
||||
v4_cell a, b, c, d;
|
||||
|
||||
if (!asker || request >= V4_MANAGE_WORDS) return 0;
|
||||
n = &asker->n;
|
||||
if (!at || request > V4_REQ_NODE_ME || request < V4_REQ_NODE_PLACE) return 0;
|
||||
n = &at->n;
|
||||
me = by_place(m, place);
|
||||
|
||||
switch (request) {
|
||||
case 0: /* NODE-ME ( -- place ) */
|
||||
case V4_REQ_NODE_ME: /* ( -- place ) */
|
||||
v4_dstack_push(&n->ds, (v4_cell)place);
|
||||
break;
|
||||
case 1: /* NODE-BORN ( -- place | -1 ) */
|
||||
v4_dstack_push(&n->ds, (v4_cell)(m->born ? m->born(m->self) : -1));
|
||||
break;
|
||||
case 2: /* NODE-WIRE ( a pa b pb -- flag ) */
|
||||
d = v4_dstack_pop(&n->ds); c = v4_dstack_pop(&n->ds); b = v4_dstack_pop(&n->ds); a = v4_dstack_pop(&n->ds);
|
||||
v4_dstack_push(&n->ds, v4_fabric_wire(m->f, place_of(a), place_of(b), place_of(c), place_of(d)) ? -1 : 0);
|
||||
break;
|
||||
case 3: /* NODE-UNWIRE ( a pa -- ) */
|
||||
b = v4_dstack_pop(&n->ds); a = v4_dstack_pop(&n->ds);
|
||||
(void)v4_fabric_unwire(m->f, place_of(a), place_of(b));
|
||||
break;
|
||||
case 4: /* NODE-SLEEP ( place -- ) */
|
||||
return 1;
|
||||
case V4_REQ_NODE_BORN: { /* ( number -- place | -1 ) */
|
||||
int p;
|
||||
a = v4_dstack_pop(&n->ds);
|
||||
v4_fabric_sleep(m->f, place_of(a));
|
||||
break;
|
||||
case 5: /* NODE-WAKE ( place -- ) */
|
||||
a = v4_dstack_pop(&n->ds);
|
||||
v4_fabric_wake(m->f, place_of(a));
|
||||
break;
|
||||
case 6: { /* NODE-KILL ( place -- ) */
|
||||
v4_fabric_node *was;
|
||||
a = v4_dstack_pop(&n->ds);
|
||||
if (place_of(a) == place) break; /* not itself: there would be no one to answer */
|
||||
was = v4_fabric_remove(m->f, place_of(a));
|
||||
if (was && m->gone) m->gone(m->self, place_of(a), was);
|
||||
break;
|
||||
if (!me || a < 1 || by_number(m, a)) return refuse(n);
|
||||
p = m->born ? m->born(m->self) : -1;
|
||||
if (p >= 0 && !v4_manage_enter(m, a, (unsigned)p, me->number)) { /* no room in the registry: the node goes again */
|
||||
v4_fabric_node *was = v4_fabric_remove(m->f, (unsigned)p);
|
||||
if (was && m->gone) m->gone(m->self, (unsigned)p, was);
|
||||
p = -1;
|
||||
}
|
||||
v4_dstack_push(&n->ds, (v4_cell)p);
|
||||
return 1;
|
||||
}
|
||||
case 7: { /* NODE-PARITY ( place number -- ) */
|
||||
case V4_REQ_NODE_WIRE: /* ( a pa b pb -- flag ) */
|
||||
d = v4_dstack_pop(&n->ds); c = v4_dstack_pop(&n->ds); b = v4_dstack_pop(&n->ds); a = v4_dstack_pop(&n->ds);
|
||||
if (!mine(m, me, place_of(a)) || !mine(m, me, place_of(c))) return refuse(n);
|
||||
v4_dstack_push(&n->ds, v4_fabric_wire(m->f, place_of(a), place_of(b), place_of(c), place_of(d)) ? -1 : 0);
|
||||
return 1;
|
||||
case V4_REQ_NODE_UNWIRE: /* ( a pa -- ) */
|
||||
b = v4_dstack_pop(&n->ds); a = v4_dstack_pop(&n->ds);
|
||||
if (!mine(m, me, place_of(a))) return refuse(n);
|
||||
(void)v4_fabric_unwire(m->f, place_of(a), place_of(b));
|
||||
return 1;
|
||||
case V4_REQ_NODE_SLEEP: /* ( number -- ) */
|
||||
case V4_REQ_NODE_WAKE:
|
||||
case V4_REQ_NODE_KILL:
|
||||
a = v4_dstack_pop(&n->ds);
|
||||
if (place != m->hera) return refuse(n);
|
||||
e = by_number(m, a);
|
||||
if (!e || e->place == place) return 1; /* not live, or Hera herself: nothing */
|
||||
if (request == V4_REQ_NODE_SLEEP) v4_fabric_sleep(m->f, e->place);
|
||||
else if (request == V4_REQ_NODE_WAKE) v4_fabric_wake(m->f, e->place);
|
||||
else {
|
||||
unsigned gone_place = e->place;
|
||||
v4_fabric_node *was = v4_fabric_remove(m->f, gone_place);
|
||||
e->number = 0;
|
||||
if (was && m->gone) m->gone(m->self, gone_place, was);
|
||||
}
|
||||
return 1;
|
||||
case V4_REQ_NODE_PARITY: { /* ( place number -- ) */
|
||||
v4_fabric_node *it;
|
||||
b = v4_dstack_pop(&n->ds); a = v4_dstack_pop(&n->ds);
|
||||
it = v4_fabric_node_at(m->f, place_of(a));
|
||||
if (it && m->parity) m->parity(m->self, place_of(a), b, &it->n);
|
||||
break;
|
||||
e = by_place(m, place_of(a));
|
||||
if (!me || !e || e == me || e->parent != me->number || e->number != b) return refuse(n);
|
||||
it = v4_fabric_node_at(m->f, e->place);
|
||||
if (it && m->parity) m->parity(m->self, e->place, b, &it->n);
|
||||
return 1;
|
||||
}
|
||||
case 8: { /* CAPSULE-OPEN ( baddr u -- flag ) */
|
||||
case V4_REQ_CAPSULE_OPEN: { /* ( baddr u -- flag ) */
|
||||
char name[64];
|
||||
unsigned i, len;
|
||||
b = v4_dstack_pop(&n->ds); a = v4_dstack_pop(&n->ds);
|
||||
if (!me) return refuse(n);
|
||||
len = b < 0 ? 0u : (unsigned)b;
|
||||
if (len == 0 || len > sizeof name || !in_memory(a) || !in_memory(a + (v4_cell)len - 1) || !m->open) {
|
||||
v4_dstack_push(&n->ds, 0);
|
||||
break;
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < len; i++) name[i] = char_at(n, a + (v4_cell)i);
|
||||
v4_dstack_push(&n->ds, m->open(m->self, name, len) ? -1 : 0);
|
||||
break;
|
||||
v4_dstack_push(&n->ds, m->open(m->self, place, name, len) ? -1 : 0);
|
||||
return 1;
|
||||
}
|
||||
case 9: /* CAPSULE-CELL ( -- w flag ) */
|
||||
case V4_REQ_CAPSULE_CELL: /* ( -- w flag ) */
|
||||
if (!me) return refuse(n);
|
||||
a = 0;
|
||||
if (m->cell && m->cell(m->self, &a)) { v4_dstack_push(&n->ds, a); v4_dstack_push(&n->ds, -1); }
|
||||
if (m->cell && m->cell(m->self, place, &a)) { v4_dstack_push(&n->ds, a); v4_dstack_push(&n->ds, -1); }
|
||||
else { v4_dstack_push(&n->ds, 0); v4_dstack_push(&n->ds, 0); }
|
||||
break;
|
||||
case 10: { /* CAPSULE-LINE ( baddr -- u | -1 ) */
|
||||
return 1;
|
||||
case V4_REQ_CAPSULE_LINE: { /* ( baddr -- u | -1 ) */
|
||||
char text[V4_MANAGE_LINE];
|
||||
int len, i;
|
||||
a = v4_dstack_pop(&n->ds);
|
||||
len = m->line ? m->line(m->self, text) : -1;
|
||||
if (!me) return refuse(n);
|
||||
len = m->line ? m->line(m->self, place, text) : -1;
|
||||
if (len > V4_MANAGE_LINE) len = V4_MANAGE_LINE;
|
||||
if (len > 0 && (!in_memory(a) || !in_memory(a + len - 1))) len = -1;
|
||||
for (i = 0; i < len; i++) char_put(n, a + i, text[i]);
|
||||
v4_dstack_push(&n->ds, (v4_cell)len);
|
||||
break;
|
||||
return 1;
|
||||
}
|
||||
case V4_REQ_NODE_CHILD: { /* ( number i -- child | 0 ) */
|
||||
unsigned k;
|
||||
v4_cell found = 0;
|
||||
b = v4_dstack_pop(&n->ds); a = v4_dstack_pop(&n->ds);
|
||||
for (k = 0; k < m->reg_cap && !found; k++)
|
||||
if (m->reg[k].number != 0 && m->reg[k].parent == a && b-- == 0) found = m->reg[k].number;
|
||||
v4_dstack_push(&n->ds, found);
|
||||
return 1;
|
||||
}
|
||||
default: /* V4_REQ_NODE_PLACE ( number -- place | -1 ) */
|
||||
a = v4_dstack_pop(&n->ds);
|
||||
e = by_number(m, a);
|
||||
v4_dstack_push(&n->ds, e ? (v4_cell)e->place : -1);
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user