feat(v4.0.0): a node looks before it writes; two neighbours no longer stop each other
MESH.md step 4, the fault found there, as ruled (section 7a): a node writes only to a neighbour that is reading, keeps what it takes in meanwhile, and loses and counts what it has no room for. Engine: two more addresses after a node's ports -- which ports have a neighbour waiting to write to it, which to read from it. Nucleus: (GATE) before every message; the messages waiting, a ring of 400 cells, dealt with when the node is idle. Of two neighbours the lower number may wait to write (ruled after it was built); NEIGHBOUR tells a node who is on each port. test_host_mesh.c, 44 checks: the case that stopped the nodes passes; six messages from each node to each at once all arrive; 800 at once, the nodes come to rest and every message arrived or was counted (287 arrived, 714 of all kinds let go). test_fabric.c: the two looks. Both widths, ASan+UBSan. POST: twelve cases handed HERE, a cell address on v4, to words that take a byte address, and so wrote into or read from the nucleus's code at cell HERE/4. Ruled: left out, marked OPEN, until HERE and the byte words are made to agree as its own step. POST is 538 cases. hosted-check on three ISAs, 538/538. Bare metal: logs/20261006-134817 (amd64), -135044 (aarch64), -135440 (riscv64). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
630d03fa4e
commit
f9c034cadd
+62
-15
@@ -14,6 +14,7 @@
|
||||
#include "v4/message.h"
|
||||
#include "v4/text.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "host_map.h"
|
||||
@@ -126,7 +127,7 @@ int main(void)
|
||||
nucleus.mem[CURRENT] = LATEST;
|
||||
nucleus.mem[SRC] = TIB;
|
||||
nucleus.mem[LINE_STATUS] = 1;
|
||||
nucleus.mem[OUT_PTR] = OUT_W;
|
||||
HOST_MESSAGES_EMPTY(&nucleus);
|
||||
|
||||
v4_fabric_init(&f, places, 3);
|
||||
hera = starforth_node(0);
|
||||
@@ -196,22 +197,68 @@ int main(void)
|
||||
CHECK(strcmp(tell(12, "5 5 + ."), "10 ") == 0 && pool[1].es.anticlock == before, "text for it no longer passes through the middle node, which executes nothing");
|
||||
}
|
||||
|
||||
/* ---- WHAT DOES NOT WORK: two neighbours that write to each other at once ----
|
||||
/* ---- two neighbours with something for each other at the same moment ----
|
||||
* A write blocks until the neighbour reads, and a node that is writing
|
||||
* is not reading. Here the far node sends text to the middle one and
|
||||
* then goes to send word of how its own text ended, which goes by the
|
||||
* middle one; the middle one does the text and goes to answer the far
|
||||
* one. Each waits for the other to read, for ever. It is the same
|
||||
* whenever messages go both ways on a wire at once, and it is because
|
||||
* passing a message on is done here by the node's own programme
|
||||
* (v4/capsule/quit.v4, (PASS-ON)), which cannot pass anything on while
|
||||
* it waits to write. docs/v4.0.0/MESH.md, step 4. This check is here
|
||||
* so that the fault is on record and is seen to go when it is put
|
||||
* right. */
|
||||
* is not reading: so a node looks before it begins a message, and of
|
||||
* two neighbours only the one with the lower number may wait to write
|
||||
* to the other (v4/capsule/core.v4, (GATE); docs/v4.0.0/MESH.md 7a).
|
||||
* Each node is told who is on each of its ports. */
|
||||
CHECK(is_empty(tell(10, "NO-ROUTES 1 1 ROUTE 11 2 ROUTE 12 2 ROUTE")) && is_empty(tell(12, "NO-ROUTES 2 DEFAULT-ROUTE")), "the row of three again");
|
||||
(void)tell(12, ": HI S\" 72 EMIT\" 11 SEND ; HI");
|
||||
CHECK(pool[1].n.asking && pool[1].n.ask_port == 3 && pool[2].n.asking && pool[2].n.ask_port == 2,
|
||||
"KNOWN FAULT: two neighbours each writing to the other wait for ever");
|
||||
CHECK(is_empty(tell(10, "11 2 NEIGHBOUR 0 3 NEIGHBOUR")) && is_empty(tell(11, "10 2 NEIGHBOUR 12 3 NEIGHBOUR")) && is_empty(tell(12, "11 2 NEIGHBOUR 0 3 NEIGHBOUR")),
|
||||
"each is told who is on the other end of its ports");
|
||||
CHECK(strstr(tell(10, "11 8 NEIGHBOUR"), "Argument out of range") != NULL && strstr(tell(10, "11 -1 NEIGHBOUR"), "Argument out of range") != NULL,
|
||||
"a port a node has not got is an error");
|
||||
/* the far node sends the middle one text, and then word of how its own
|
||||
* text ended, which goes by the middle one; the middle one does the
|
||||
* text and answers the far one: the two messages meet on one wire */
|
||||
CHECK(strcmp(tell(12, ": HI S\" 72 EMIT\" 11 SEND ; HI"), "H") == 0 && printed_from == 11 && ended == 1 && ended_from == 12,
|
||||
"from the far end to the middle, with the answers crossing: \"%s\" from %ld", printed, (long)printed_from);
|
||||
CHECK(waiting(hera) && waiting(mid) && waiting(far), "and all three are waiting again");
|
||||
|
||||
/* every node sends every other a number of messages, all at once: each
|
||||
* counts what it is sent */
|
||||
CHECK(is_empty(tell(10, "VARIABLE GOT : HIT 1 GOT +! ; VARIABLE WHO VARIABLE SENT : BURST WHO ! 0 DO S\" HIT\" WHO @ SEND 1 SENT +! LOOP ;")) &&
|
||||
is_empty(tell(11, "VARIABLE GOT : HIT 1 GOT +! ; VARIABLE WHO VARIABLE SENT : BURST WHO ! 0 DO S\" HIT\" WHO @ SEND 1 SENT +! LOOP ;")) &&
|
||||
is_empty(tell(12, "VARIABLE GOT : HIT 1 GOT +! ; VARIABLE WHO VARIABLE SENT : BURST WHO ! 0 DO S\" HIT\" WHO @ SEND 1 SENT +! LOOP ;")), "each node is given a word to count with and one to send with");
|
||||
{
|
||||
const char *r = tell(10, ": GO S\" 6 10 BURST 6 12 BURST\" 11 SEND S\" 6 11 BURST 6 10 BURST\" 12 SEND 6 11 BURST 6 12 BURST ; GO");
|
||||
CHECK(is_empty(r), "six messages from each node to each other, all at once: \"%s\"", r);
|
||||
CHECK(waiting(hera) && waiting(mid) && waiting(far), "all three come to rest");
|
||||
CHECK(strcmp(tell(10, "GOT @ . (LOST) @ ."), "12 1 ") == 0 && strcmp(tell(11, "GOT @ . (LOST) @ ."), "12 0 ") == 0 && strcmp(tell(12, "GOT @ . (LOST) @ ."), "12 0 ") == 0,
|
||||
"every one of them arrived, and none was let go: \"%s\"", printed);
|
||||
}
|
||||
|
||||
/* ---- more than a node has room to keep ----
|
||||
* A node that takes messages in while it waits to write keeps them, and
|
||||
* when it has no room for one more it lets that one go and counts it.
|
||||
* Far more are sent here than the nodes can keep. */
|
||||
{
|
||||
long got = 0, lost = 0, sent = 0, v;
|
||||
unsigned k;
|
||||
static const v4_cell who[3] = { 10, 11, 12 };
|
||||
const char *r;
|
||||
CHECK(is_empty(tell(10, "0 GOT ! 0 SENT !")) && is_empty(tell(11, "0 GOT ! 0 SENT !")) && is_empty(tell(12, "0 GOT ! 0 SENT !")), "the counts begin again");
|
||||
r = tell(10, ": GO2 S\" 200 10 BURST 200 12 BURST\" 11 SEND S\" 200 11 BURST 200 10 BURST\" 12 SEND 200 11 BURST 200 12 BURST ; GO2");
|
||||
CHECK(strcmp(r, "(still running)") != 0, "two hundred from each to each: it ends");
|
||||
CHECK(waiting(hera) && waiting(mid) && waiting(far), "and all three come to rest, none waiting to write");
|
||||
for (k = 0; k < 3; k++) {
|
||||
r = tell(who[k], "GOT @ .");
|
||||
v = strtol(r, NULL, 10); got += v;
|
||||
CHECK(v > 0 && v <= 400, "node %ld took %ld of the 400 for it", (long)who[k], v);
|
||||
r = tell(who[k], "(LOST) @ .");
|
||||
lost += strtol(r, NULL, 10);
|
||||
r = tell(who[k], "SENT @ .");
|
||||
sent += strtol(r, NULL, 10);
|
||||
CHECK(pool[k].n.mem[MQ_COUNT] == 0, "node %ld has none left waiting", (long)who[k]);
|
||||
}
|
||||
lost -= 1; /* the one for node 99, earlier */
|
||||
/* what is let go is of every kind: the text that would have set a
|
||||
* node sending, the answers to text, as well as what was sent */
|
||||
printf(" of %ld messages the nodes sent each other at once %ld arrived; %ld messages of all kinds were let go for want of room\n", sent, got, lost);
|
||||
CHECK(lost > 0, "there was not room for all of them");
|
||||
CHECK(got <= sent && got + lost >= sent, "every message sent either arrived or was counted: %ld sent, %ld arrived, %ld let go", sent, got, lost);
|
||||
CHECK(strcmp(tell(12, "7 8 * ."), "56 ") == 0 && printed_from == 12, "and the nodes go on as before");
|
||||
}
|
||||
|
||||
printf(" %d checks, %d failures\n", checks, failures);
|
||||
return failures != 0;
|
||||
|
||||
Reference in New Issue
Block a user