safety commit
This commit is contained in:
@@ -26,7 +26,10 @@
|
||||
* -12 NODE-KILL ( number -- ) Hera; not herself; a number not
|
||||
* live does nothing. The node's
|
||||
* children are not removed, as v3,
|
||||
* and become Hera's children.
|
||||
* and become Hera's children. The
|
||||
* kernel puts a GONE about it on
|
||||
* every live node's wire from its
|
||||
* parent: no node hands one on.
|
||||
* -13 NODE-PARITY ( place number -- ) for a node the asker birthed,
|
||||
* under the number it was born as
|
||||
* -14 CAPSULE-OPEN ( baddr u -- flag ) any node in the registry: the
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Nothing here uses the C library: the bare-metal kernel links this file.
|
||||
*/
|
||||
#include "v4/manage.h"
|
||||
#include "v4/message.h"
|
||||
|
||||
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",
|
||||
@@ -45,6 +46,28 @@ 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);
|
||||
}
|
||||
/* THE KERNEL TELLS A NODE'S GOING (MESH.md 9a, ruled 2026-10-16). Every live node that has a parent, and is
|
||||
* wired to it, is put a GONE about `gone` on the wire from its parent, as if its parent had sent it: so the
|
||||
* node believes it, its parent being its centre (7b.4). No node hands a GONE on. A wire with no room for it
|
||||
* is not waited for: that node is not told (as an answer whose way back is full, 7d.6). */
|
||||
static void tell_gone(const v4_manage *m, v4_cell gone)
|
||||
{
|
||||
unsigned k, port;
|
||||
v4_cell hd[V4_WIRE_HEADER], text[1];
|
||||
for (k = 0; k < m->reg_cap; k++) {
|
||||
const v4_manage_entry *c = &m->reg[k], *p;
|
||||
if (c->number == 0 || c->parent == 0 || !(p = by_number(m, c->parent))) continue;
|
||||
for (port = 0; port < V4_PORTS; port++) {
|
||||
const v4_wire *w = &m->f->place[c->place].wire[port];
|
||||
if (w->kind != V4_WIRE_NODE || w->node != p->place || !w->rx) continue;
|
||||
hd[0] = c->number; hd[1] = p->number; hd[2] = V4_MSG_GONE; hd[3] = 16; hd[4] = 0; hd[5] = 0; hd[6] = 4;
|
||||
text[0] = gone;
|
||||
(void)v4_wire_put(w->rx, hd, text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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; }
|
||||
|
||||
@@ -117,6 +140,7 @@ int v4_manage_serve(const v4_manage *m, unsigned place, v4_cell request)
|
||||
* parent, so a node born later under it inherits nothing (the final review of step 7) */
|
||||
for (k = 0; k < m->reg_cap; k++) if (m->reg[k].number != 0 && m->reg[k].parent == gone_number) m->reg[k].parent = me->number;
|
||||
if (was && m->gone) m->gone(m->self, gone_place, was);
|
||||
tell_gone(m, gone_number);
|
||||
}
|
||||
return 1;
|
||||
case V4_REQ_NODE_PARITY: { /* ( place number -- ) */
|
||||
|
||||
@@ -452,7 +452,6 @@ int main(void)
|
||||
CHECK(strstr(tell(10, "RS1"), "UNKNOWN WORD") != NULL && strstr(tell(10, "ZERO"), "UNKNOWN WORD") != NULL, "nor anything POST's cases defined: POST leaves nothing, as in v3: \"%s\"", printed);
|
||||
CHECK(load(10, "centre.4th") == 0, "she takes in what a node that births needs");
|
||||
CHECK(load(10, "hera.4th") == 0, "and her own capsule, which makes it Hera");
|
||||
CHECK(strcmp(tell(10, "(GONE-HOOK) @ 0= ."), "0 ") == 0, "centre.4th has put GONE-DOWN in her (GONE-HOOK)");
|
||||
CHECK(strcmp(tell(10, "NODE-ME ."), "0 ") == 0 && refused == 0, "she asks where she is, by the word centre.4th made, and is answered");
|
||||
CHECK(told(10, "(SEAL)"), "that is the system it comes back to");
|
||||
|
||||
@@ -717,9 +716,9 @@ int main(void)
|
||||
CHECK(node_numbered(10)->mem[LOST] == hera_lost && node_numbered(11)->mem[LOST] == 0 && node_numbered(13)->mem[LOST] == 0 && node_numbered(14)->mem[LOST] == 0
|
||||
&& waiting(10) && waiting(11) && waiting(13) && waiting(14), "nothing was let go in all of this, and all wait again: Hera %ld (%ld before)",
|
||||
(long)node_numbered(10)->mem[LOST], (long)hera_lost);
|
||||
/* Review Focus 4 (the final review of step 7): after UNIT-KILL no node still lists a removed node as its
|
||||
* child -- the next KILL would tell it, and with no way to it that would be an error. */
|
||||
CHECK(strcmp(tell(10, "20 (WHICH) ."), "-1 ") == 0, "Hera no longer lists node 20 among the nodes she birthed: \"%s\"", printed);
|
||||
/* Review Focus 4 (the final review of step 7): after UNIT-KILL nothing still holds a removed node as a
|
||||
* child, and the next KILL tells only the nodes there are. */
|
||||
CHECK(strcmp(tell(10, "10 0 NODE-CHILD . 10 1 NODE-CHILD . 10 2 NODE-CHILD . 10 3 NODE-CHILD ."), "11 13 14 0 ") == 0, "the kernel lists only the nodes there are as Hera's: \"%s\"", printed);
|
||||
CHECK(told(10, "14 KILL") && node_numbered(14) == NULL && strcmp(tell(13, "1 2 + ."), "3 ") == 0,
|
||||
"and a KILL after UNIT-KILL tells only the nodes there are: it completes, and the rest go on: \"%s\"", printed);
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* served, as the kernel does when the node writes its number to port 0. */
|
||||
#include "v4/fabric.h"
|
||||
#include "v4/manage.h"
|
||||
#include "v4/message.h"
|
||||
#include "v4/wire.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -18,6 +20,7 @@ static int used[NODES];
|
||||
static v4_place places[NODES];
|
||||
static v4_fabric f;
|
||||
static v4_manage_entry reg[NODES];
|
||||
static v4_wire_queue queues[32];
|
||||
static unsigned gone_count, parity_count;
|
||||
static v4_cell parity_number;
|
||||
static v4_manage m;
|
||||
@@ -75,6 +78,7 @@ int main(void)
|
||||
|
||||
printf("v4 manage tests: V4_CELL_BITS=%d\n", V4_CELL_BITS);
|
||||
v4_fabric_init(&f, places, NODES);
|
||||
v4_fabric_queues(&f, queues, 32);
|
||||
memset(&m, 0, sizeof m);
|
||||
m.f = &f; m.reg = reg; m.reg_cap = NODES; m.born = born; m.gone = gone;
|
||||
m.open = open_; m.cell = cell_; m.line = line_; m.parity = parity_;
|
||||
@@ -163,6 +167,36 @@ int main(void)
|
||||
}
|
||||
CHECK(place_of(h, 12) == -1 && place_of(h, 10) == (v4_cell)h, "NODE-PLACE of a number not live is -1");
|
||||
|
||||
/* ---- THE KERNEL TELLS A NODE'S GOING (MESH.md 9a, ruled 2026-10-16 after the final review of step 7) ----
|
||||
* When Hera kills a node, the kernel puts a GONE on the wire of every live node from its parent, as if its
|
||||
* parent had sent it -- so that the node believes it, its parent being its centre -- and no node hands one
|
||||
* on. Here: Hera (10) births 20 and 40; 20 births 21, wired 20:3 -- 21:2; 40 is killed. */
|
||||
{
|
||||
v4_cell p20, p21, p40;
|
||||
v4_cell hd[V4_WIRE_HEADER];
|
||||
const v4_wire_queue *q;
|
||||
p20 = birth(h, 20); p40 = birth(h, 40);
|
||||
p21 = birth((unsigned)p20, 21);
|
||||
push(h, (v4_cell)h); push(h, 6); push(h, p20); push(h, 6);
|
||||
CHECK(p20 >= 0 && p21 >= 0 && p40 >= 0 && v4_manage_serve(&m, h, V4_REQ_NODE_WIRE) == 1 && pop(h) == -1, "Hera's port 6 is wired to node 20's");
|
||||
push((unsigned)p20, p20); push((unsigned)p20, 3); push((unsigned)p20, p21); push((unsigned)p20, 2);
|
||||
CHECK(v4_manage_serve(&m, (unsigned)p20, V4_REQ_NODE_WIRE) == 1 && pop((unsigned)p20) == -1, "node 20's port 3 is wired to node 21's port 2");
|
||||
push(h, 40);
|
||||
CHECK(v4_manage_serve(&m, h, V4_REQ_NODE_KILL) == 1 && place_of(h, 40) == -1, "Hera kills 40");
|
||||
q = places[p21].wire[2].rx;
|
||||
CHECK(q && q->used == V4_WIRE_HEADER + 1u && q->arrived, "a message has come to node 21 on the wire from its parent: %u cells", q ? q->used : 0u);
|
||||
if (q && q->used) {
|
||||
v4_wire_queue copy = *q;
|
||||
v4_wire_first(©);
|
||||
CHECK(v4_wire_look(©, hd) == V4_WIRE_DONE && hd[0] == 21 && hd[1] == 20 && hd[2] == V4_MSG_GONE && hd[6] == 4
|
||||
&& copy.cell[(copy.head + V4_WIRE_HEADER) % V4_WIRE_CELLS] == 40,
|
||||
"a GONE about 40, to 21, from its parent 20: %ld %ld %ld len %ld", (long)hd[0], (long)hd[1], (long)hd[2], (long)hd[6]);
|
||||
}
|
||||
q = places[p20].wire[6].rx;
|
||||
CHECK(q && q->used == V4_WIRE_HEADER + 1u, "and one to node 20, from Hera, on the wire from her: %u cells", q ? q->used : 0u);
|
||||
CHECK(places[h].wire[6].rx == 0 || places[h].wire[6].rx->used == 0, "Hera is sent none: she has no parent, and kills");
|
||||
}
|
||||
|
||||
printf(" %d checks, %d failures\n", checks, failures);
|
||||
return failures != 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user