feat(v4.0.0): every message begins through the wait -- a stuck node holds up no one
(GATE) offers a message's first word and sleeps until it is taken, taking in whatever is written to the node meanwhile; (PAY) offers every refusal owed at once, one to a port; a node that owes one sleeps in the wait. Writing without looking, looking again and again, and the lower-number rule are gone. Text from the console for a node whose own text waits to begin a message ends that text Interrupted. The lone node's hosts serve an offer as a write. MESH.md 7c; plan step 6d task 2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
075385ab63
commit
482cc75faf
+8
-1
@@ -87,6 +87,8 @@
|
||||
#define MQ_TAIL (BUF0_W - 36) /* where the next will go, */
|
||||
#define MQ_COUNT (BUF0_W - 37) /* and how many cells they take */
|
||||
#define AWAIT_FROM (BUF0_W - 39) /* the node whose word of how text ended is waited for */
|
||||
#define GATE_WORD (BUF0_W - 32) /* the first word of a message that is being offered */
|
||||
#define PAY_K (BUF0_W - 123) /* for each port, which refusal owed is offered there, counted from 1; 0: none. V4_PORTS cells */
|
||||
#define GATE_PORT (BUF0_W - 38) /* the port address a message is about to be begun on */
|
||||
#define NEAR (BUF0_W - 64) /* for each port, the number of the node on the other end; 0: not told */
|
||||
#define MQ_HDR (BUF0_W - 56) /* a message being taken in: its seven words and the port it came on */
|
||||
@@ -125,7 +127,7 @@ typedef char host_map_ports_fit[(V4_PORTS <= 8u) ? 1 : -1];
|
||||
/* the messages waiting are above the dictionary */
|
||||
typedef char host_map_queue_fits[(MQ_W >= DICT_END_W) ? 1 : -1];
|
||||
/* the ports, with the offers and the wait after them, end below the cells that follow */
|
||||
typedef char host_map_port_block_fits[(PORT + 2 * (v4_cell)V4_PORTS + 5 <= BUF0_W - 115) ? 1 : -1];
|
||||
typedef char host_map_port_block_fits[(PORT + 2 * (v4_cell)V4_PORTS + 5 <= PAY_K && PAY_K + (v4_cell)V4_PORTS <= BUF0_W - 115) ? 1 : -1];
|
||||
|
||||
/* How many slots, from slot 0, a branch may sit in on a node this size: those
|
||||
* whose address field reaches every word of it. */
|
||||
@@ -198,6 +200,11 @@ static int host_load(v4_text *tx, v4_node *n, const char *const *files, unsigned
|
||||
v4_text_constant(tx, "-PORTS", -(v4_cell)V4_PORTS);
|
||||
v4_text_constant(tx, "(NEAR)", NEAR);
|
||||
v4_text_constant(tx, "(GATE-PORT)", GATE_PORT);
|
||||
v4_text_constant(tx, "(GATE-WORD)", GATE_WORD);
|
||||
v4_text_constant(tx, "(PAY-K)", PAY_K);
|
||||
v4_text_constant(tx, "PORTS-1", (v4_cell)V4_PORTS - 1);
|
||||
v4_text_constant(tx, "(OFFER)", PORT + (v4_cell)V4_PORT_OFFER);
|
||||
v4_text_constant(tx, "(WAIT)", PORT + (v4_cell)V4_PORT_WAIT);
|
||||
v4_text_constant(tx, "(AWAIT-FROM)", AWAIT_FROM);
|
||||
v4_text_constant(tx, "(MQ)", MQ_W);
|
||||
v4_text_constant(tx, "(MQ-END)", MQ_W + MQ_CELLS);
|
||||
|
||||
+68
-22
@@ -112,6 +112,10 @@ static unsigned starforth_node(unsigned k)
|
||||
return (unsigned)id;
|
||||
}
|
||||
|
||||
/* The same, answering with what has been printed: for when a node is
|
||||
* spinning and the fabric never comes to rest. */
|
||||
static const char *said(v4_cell node, const char *text) { (void)tell(node, text); return printed; }
|
||||
|
||||
static int waiting(unsigned id)
|
||||
{
|
||||
const v4_node *n = &v4_fabric_node_at(&f, id)->n;
|
||||
@@ -364,9 +368,10 @@ int main(void)
|
||||
{
|
||||
CHECK(is_empty(tell(11, "0 GOT !")) && is_empty(tell(11, "12 AWAIT .")) && pool[1].n.mem[AWAIT_FROM] == 12, "node 11 waits on 12 again");
|
||||
CHECK(is_empty(tell(10, ": F40 40 0 DO S\" HIT\" 11 SEND LOOP ; F40")) && pool[1].n.mem[OWED_COUNT] == 0, "node 10 sends it as many messages as it has room for");
|
||||
(void)tell(10, ": ONE S\" HIT\" 11 SEND 12 NO-ROUTE 12 11 GONE 11 AWAIT . ; ONE");
|
||||
/* node 11 does what it has kept before it pays what it owes (7b.3): forty answers come first */
|
||||
(void)tell(10, ": ONE S\" HIT\" 11 SEND 12 NO-ROUTE 12 11 GONE 41 0 DO 11 AWAIT DROP LOOP ; ONE");
|
||||
CHECK(strstr(printed, "Message refused") != NULL && pool[0].n.mem[AWAIT_FROM] == 0,
|
||||
"it sends one more, for which there is no room, ends node 11's wait, and waits for node 11's answer: its own wait ends, the message refused: \"%s\"", printed);
|
||||
"it sends one more, for which there is no room, ends node 11's wait, and waits for node 11's answers: after the forty, its wait ends, the message refused: \"%s\"", printed);
|
||||
CHECK(strtol(tell(11, "GOT @ ."), NULL, 10) == 40 && is_empty(tell(10, "12 3 ROUTE")) && is_empty(tell(11, "12 3 ROUTE")), "node 11 did the forty it had kept; the ways are told again");
|
||||
}
|
||||
|
||||
@@ -393,34 +398,75 @@ int main(void)
|
||||
CHECK(is_empty(tell(10, "66 NO-ROUTE")) && waiting(hera) && waiting(mid) && waiting(far), "the way is forgotten, and all three are at rest");
|
||||
}
|
||||
|
||||
/* a node that owes a refusal to a node that is stuck is not stuck itself */
|
||||
CHECK(is_empty(tell(12, "NO-ROUTES 1 3 ROUTE 10 3 ROUTE 11 2 ROUTE")) && is_empty(tell(11, "55 3 ROUTE")), "node 12 has no way for 55; node 11 is told the way to 55 is by node 12");
|
||||
/* ---- a node that is stuck holds up no one (MESH.md 7c) ------------------- */
|
||||
v4_fabric_gone_error(&f, V4_ERROR_NO_ONE);
|
||||
|
||||
/* From here a node is spinning, so the fabric never comes to rest: said()
|
||||
* is tell(), answering with what was printed by the time it gave up. */
|
||||
|
||||
/* a refusal owed to a stuck node whose number is the lower */
|
||||
CHECK(is_empty(said(12, "NO-ROUTES 1 3 ROUTE 10 3 ROUTE 11 2 ROUTE")) && is_empty(said(11, "55 3 ROUTE")), "node 12 has no way for 55; node 11 is told the way to 55 is by node 12");
|
||||
CHECK(strcmp(tell(11, ": C1 S\" 1 DROP\" 55 SEND BEGIN 0 UNTIL ; C1"), "(still running)") == 0, "node 11 sends 55 a message and is then stuck in a loop");
|
||||
CHECK(pool[2].n.mem[OWED_COUNT] == 1, "node 12 owes node 11 a refusal, and cannot give it: node 11 is not reading");
|
||||
(void)tell(12, "7 8 * .");
|
||||
CHECK(strcmp(printed, "56 ") == 0 && printed_from == 12, "node 12 goes on doing what it is sent: \"%s\"", printed);
|
||||
CHECK(strcmp(said(12, "7 8 * ."), "56 ") == 0 && printed_from == 12, "node 12 goes on doing what it is sent: \"%s\"", printed);
|
||||
{
|
||||
v4_uheat_t clock = pool[2].es.anticlock;
|
||||
unsigned k;
|
||||
for (k = 0; k < 1000; k++) (void)v4_fabric_step(&f);
|
||||
CHECK(v4_node_in_wait(&pool[2].n) && pool[2].es.anticlock == clock && pool[2].n.mem[OWED_COUNT] == 1, "between times it sleeps in the wait, still owing, and executes nothing");
|
||||
}
|
||||
CHECK(strcmp(said(10, ": X12 S\" 66 EMIT\" 12 SEND ; X12"), "B") == 0 && printed_from == 12, "another node writes to it and is answered: \"%s\"", printed);
|
||||
|
||||
/* a node that is waiting to write to a node finds out when that node is removed */
|
||||
(void)tell(12, ": TO11 S\" 1 DROP\" 11 SEND 65 EMIT ; TO11");
|
||||
CHECK(ended == 0, "node 12 sends node 11 a message: node 11 is not reading, and node 12 waits to write to it");
|
||||
/* two refusals owed: one to the stuck node, one to a node that waits for it */
|
||||
CHECK(is_empty(said(10, "77 3 ROUTE")), "node 10 is told the way to 77 is by node 12, which has none");
|
||||
CHECK(strstr(said(10, ": W77B S\" 1 DROP\" 77 SEND 77 AWAIT . ; W77B"), "Message refused") != NULL && pool[0].n.mem[AWAIT_FROM] == 0 && pool[2].n.mem[OWED_COUNT] == 1,
|
||||
"node 10 sends 77 a message and waits: node 12, which still owes the stuck node, tells node 10 it was refused: \"%s\"", printed);
|
||||
CHECK(is_empty(said(10, "77 NO-ROUTE")), "the way is forgotten");
|
||||
|
||||
/* a line that must begin a message to the stuck node waits, and the node takes in what comes */
|
||||
CHECK(is_empty(said(10, ": TO11 S\" 1 DROP\" 11 SEND 65 EMIT ; TO11")) && ended == 0 && v4_node_in_wait(&pool[0].n) && !pool[0].n.asking,
|
||||
"node 10 sends the stuck node a message: its line waits in the wait, not blocked writing");
|
||||
{
|
||||
v4_cell kept = pool[0].n.mem[MQ_COUNT];
|
||||
CHECK(is_empty(said(12, "7 8 * .")) && ended == 0 && pool[0].n.mem[MQ_COUNT] > kept && v4_node_in_wait(&pool[0].n),
|
||||
"text from the console for node 12 comes to node 10: it keeps it, and its line goes on waiting");
|
||||
}
|
||||
{
|
||||
const char *r = said(10, "66 EMIT");
|
||||
CHECK(strstr(r, "Interrupted\n") != NULL && strstr(r, "A") == NULL && strstr(r, "B") != NULL && strstr(r, "Interrupted\n") < strstr(r, "B"),
|
||||
"text from the console for node 10 itself ends the line that waited, with an error that says so, and is then done: \"%s\"", r);
|
||||
CHECK(strstr(r, "56 ") != NULL && ended == 3, "and what it kept for node 12 is passed on and done: \"%s\", %d ended", r, ended);
|
||||
}
|
||||
|
||||
/* the stuck node is removed while a line waits to begin a message to it */
|
||||
CHECK(is_empty(said(10, "TO11")) && ended == 0 && v4_node_in_wait(&pool[0].n), "node 10's line waits on the stuck node again");
|
||||
CHECK(v4_fabric_remove(&f, mid) == &pool[1], "node 11 is removed");
|
||||
(void)tell(10, "1 DROP");
|
||||
CHECK(strstr(printed, "No one on that port") != NULL && strstr(printed, "A") == NULL, "node 12's line ends in an error that says no one is there: \"%s\"", printed);
|
||||
{
|
||||
unsigned k;
|
||||
for (k = 0; k < 200000 && ended == 0; k++) (void)v4_fabric_step(&f);
|
||||
CHECK(strstr(printed, "No one on that port") != NULL && strstr(printed, "A") == NULL && ended == 1, "the line ends in an error that says no one is there: \"%s\"", printed);
|
||||
}
|
||||
step_cap = 20000000;
|
||||
CHECK(strcmp(tell(12, "7 8 * ."), "56 ") == 0 && pool[2].n.mem[OWED_COUNT] == 0 && waiting(far) && waiting(hera),
|
||||
"it goes on, the refusal it owed node 11 let go: it owes nothing and is at rest");
|
||||
CHECK(strcmp(said(12, "7 8 * ."), "56 ") == 0 && pool[2].n.mem[OWED_COUNT] == 0 && waiting(far) && !v4_node_in_wait(&pool[2].n) && waiting(hera),
|
||||
"node 12 goes on, the refusal it owed node 11 let go: it owes nothing and is at rest");
|
||||
|
||||
/* THE LIMIT (MESH.md 7b.7): a refusal owed to a neighbour whose number is the higher is written
|
||||
* without looking, as any message to it is, so a node that is stuck holds up a neighbour that owes
|
||||
* it one -- until it is removed */
|
||||
/* a refusal owed to a stuck node whose number is the higher */
|
||||
step_cap = 3000000;
|
||||
CHECK(is_empty(tell(12, "55 3 ROUTE")), "node 12 is told the way to 55 is by node 10, which has none");
|
||||
CHECK(strcmp(tell(12, ": C2 S\" 1 DROP\" 55 SEND BEGIN 0 UNTIL ; C2"), "(still running)") == 0 && pool[0].n.asking && pool[0].n.mem[OWED_COUNT] == 1,
|
||||
"node 12 sends 55 a message and is then stuck in a loop: node 10 owes it a refusal, writes it, and is blocked");
|
||||
v4_fabric_gone_error(&f, V4_ERROR_NO_ONE);
|
||||
CHECK(v4_fabric_remove(&f, far) == &pool[2], "node 12 is removed");
|
||||
CHECK(is_empty(said(12, "55 3 ROUTE")), "node 12 is told the way to 55 is by node 10, which has none");
|
||||
CHECK(strcmp(tell(12, ": C2 S\" 1 DROP\" 55 SEND BEGIN 0 UNTIL ; C2"), "(still running)") == 0 && pool[0].n.mem[OWED_COUNT] == 1 && !pool[0].n.asking,
|
||||
"node 12 sends 55 a message and is then stuck in a loop: node 10 owes it a refusal, and is not blocked writing it");
|
||||
step_cap = 20000000;
|
||||
CHECK(strcmp(tell(10, "1 2 + ."), "3 ") == 0 && pool[0].n.mem[OWED_COUNT] == 0 && waiting(hera), "node 10 is let go, lets the refusal go, and goes on: \"%s\"", printed);
|
||||
CHECK(strcmp(said(10, "1 2 + ."), "3 ") == 0 && pool[0].n.mem[OWED_COUNT] == 1, "node 10 goes on doing what it is sent, still owing: \"%s\"", printed);
|
||||
{
|
||||
v4_uheat_t clock;
|
||||
unsigned k;
|
||||
for (k = 0; k < 1000; k++) (void)v4_fabric_step(&f);
|
||||
clock = pool[0].es.anticlock;
|
||||
for (k = 0; k < 1000; k++) (void)v4_fabric_step(&f);
|
||||
CHECK(v4_node_in_wait(&pool[0].n) && pool[0].es.anticlock == clock, "and sleeps in the wait between times");
|
||||
}
|
||||
CHECK(v4_fabric_remove(&f, far) == &pool[2], "node 12 is removed");
|
||||
CHECK(strcmp(said(10, "1 2 + ."), "3 ") == 0 && pool[0].n.mem[OWED_COUNT] == 0 && waiting(hera) && !v4_node_in_wait(&pool[0].n), "node 10 lets the refusal go and is at rest: \"%s\"", printed);
|
||||
|
||||
printf(" %d checks, %d failures\n", checks, failures);
|
||||
return failures != 0;
|
||||
|
||||
@@ -213,6 +213,7 @@ static int run_line(long max)
|
||||
while (steps < max && idle < 64) {
|
||||
(void)v4_exec_step_word(&n, &es, &h);
|
||||
steps++;
|
||||
(void)v4_node_offer_as_write(&n); /* in the wait: what it offers is a write, the kernel and the console taking at once */
|
||||
if (n.asking && n.ask_port == 0) { kernel_serve(); v4_node_port_served(&n); continue; } /* a request */
|
||||
if (n.asking && n.ask_port == CONSOLE_PORT) { /* a word of a message from the node */
|
||||
v4_cell word = n.request;
|
||||
|
||||
@@ -506,8 +506,8 @@ int main(void)
|
||||
/* a node is killed while its neighbour is writing to it */
|
||||
step_limit = 3000000ul;
|
||||
CHECK(strcmp(tell(14, ": SPIN BEGIN 0 UNTIL ; SPIN"), "(still running)") == 0, "node 14 is stuck in a loop that never ends");
|
||||
CHECK(strcmp(tell(12, ": TO14 S\" 65 EMIT\" 14 SEND ; TO14"), "(still running)") == 0 && node_numbered(12)->asking,
|
||||
"node 12, beside it, sends it text: 14 never reads, and 12 is blocked writing to it");
|
||||
CHECK(strcmp(tell(12, ": TO14 S\" 65 EMIT\" 14 SEND ; TO14"), "(still running)") == 0 && v4_node_in_wait(node_numbered(12)) && !node_numbered(12)->asking,
|
||||
"node 12, beside it, sends it text: 14 never reads, and 12 waits to begin the message, in the wait");
|
||||
{
|
||||
unsigned born = born_count;
|
||||
const char *r = tell(10, "14 KILL 65 EMIT");
|
||||
@@ -551,8 +551,8 @@ int main(void)
|
||||
/* Hera blocked writing to a node that is stuck: a line from the console lets her go (MESH.md 7b.7) */
|
||||
step_limit = 3000000ul;
|
||||
CHECK(strcmp(tell(11, ": SPIN BEGIN 0 UNTIL ; SPIN"), "(still running)") == 0, "node 11 is stuck in a loop");
|
||||
CHECK(strcmp(tell(10, ": T11 S\" 1 DROP\" 11 SEND 67 EMIT ; T11"), "(still running)") == 0 && node_numbered(10)->asking,
|
||||
"Hera sends it text: its number is the higher, so she writes without looking, and is blocked");
|
||||
CHECK(strcmp(tell(10, ": T11 S\" 1 DROP\" 11 SEND 67 EMIT ; T11"), "(still running)") == 0 && v4_node_in_wait(node_numbered(10)) && !node_numbered(10)->asking,
|
||||
"Hera sends it text: it never reads, and she waits to begin the message, in the wait");
|
||||
{
|
||||
const char *r = tell(10, "11 KILL 68 EMIT");
|
||||
CHECK(strstr(r, "Interrupted\n") != NULL && strstr(r, "D") != NULL && strstr(r, "C") == NULL && strstr(r, "Interrupted\n") < strstr(r, "D"),
|
||||
|
||||
Reference in New Issue
Block a user