From ec817a8264a1ff1b2feae1f60881b8f0554e69cf Mon Sep 17 00:00:00 2001 From: rajames Date: Thu, 8 Oct 2026 01:00:33 -0400 Subject: [PATCH] fix(v4.0.0): a waiting node goes on passing on and paying; KILL is not held by a stuck node Found in the five-node test, each with a check that failed first: - A node with answers it could not give to two stuck senders began no text at all. It now holds back only text from a sender whose own answer is still with it. - KILL waited to tell a stuck node, and a typed line that broke it left the nodes after it untold. GONE is put with the messages waiting, as how text ended is, and goes when it can. - So that 'tell, then wait' still works, AWAIT does what (IDLE) does but for beginning text: it looks through the messages waiting, offers what is to be passed on and what is owed, and sleeps in the wait. A waiting node no longer keeps back what passes through it. - A node in the wait with an offer on a port that turns out to have nothing on it is woken and told so (which port: 2 * V4_PORTS + k); no error is raised on it. (GATE) makes it error 18; (IDLE) and AWAIT let the message go. Before, removing a node raised 'No one on that port' on the unrelated text of a neighbour that had something queued for it. make -C v4 test and sanitize at both widths, hosted-check. Co-Authored-By: Claude Opus 5.5 --- capsules/v4/nucleus-64.f18 | Bin 58536 -> 58416 bytes v4/capsule/core.v4 | 20 +++++--- v4/capsule/quit.v4 | 102 ++++++++++++++++++------------------- v4/include/v4/node.h | 12 ++++- v4/src/fabric.c | 2 +- v4/src/node.c | 16 +++++- v4/tests/test_fabric.c | 8 +-- v4/tests/test_host_mesh.c | 17 ++++--- v4/tests/test_host_unit.c | 52 +++++++++++-------- 9 files changed, 130 insertions(+), 99 deletions(-) diff --git a/capsules/v4/nucleus-64.f18 b/capsules/v4/nucleus-64.f18 index 62486314ed128d690a507382086ef233a6175c7c..b615b42e6043d7b06a9f7c16ddb636bbf406eb4a 100644 GIT binary patch literal 58416 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

pqVO{9oW#VqW$b;vm-<*5}yz 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 NsHFaL-Jjo^{(nh?(offers & (1u << k)) && f->place[i].wire[k].kind == V4_WIRE_NONE) { done += (unsigned)v4_node_port_gone(n, f->gone_error); break; } + if ((n->offers & (1u << k)) && f->place[i].wire[k].kind == V4_WIRE_NONE) { done += (unsigned)v4_node_offer_gone(n, k); break; } } } diff --git a/v4/src/node.c b/v4/src/node.c index c929216f..ff8cf626 100644 --- a/v4/src/node.c +++ b/v4/src/node.c @@ -243,6 +243,14 @@ int v4_node_offer_taken(v4_node *n, unsigned k) return 1; } +int v4_node_offer_gone(v4_node *n, unsigned k) +{ + if (n->error_reg < 0 || n->fault_vector < 0 || n->stopped) return 0; + if (!v4_node_in_wait(n) || k >= V4_PORTS || !(n->offers & (1u << k))) return 0; + v4_node_port_give(n, 2u * V4_PORTS + k, 0); + return 1; +} + int v4_node_offer_as_write(v4_node *n) { unsigned k; @@ -280,8 +288,12 @@ unsigned v4_node_words_since_look(const v4_node *n) int v4_node_port_gone(v4_node *n, v4_cell code) { if (code == 0 || n->error_reg < 0 || n->fault_vector < 0 || n->stopped) return 0; - if (n->asking) { n->asking = 0; if (n->offer_asked) { n->offer_asked = 0; n->reading = 0; n->waiting = 0; n->offers = 0; } } - else if (v4_node_in_wait(n) && n->offers != 0) { n->reading = 0; n->waiting = 0; n->offers = 0; } + if (n->asking && n->offer_asked) { /* what it wrote was an offer: it is told, not faulted */ + n->asking = 0; n->offer_asked = 0; + v4_node_port_give(n, 2u * V4_PORTS + n->ask_port, 0); + return 1; + } + if (n->asking) n->asking = 0; else if (n->reading && !n->given && n->read_port != V4_PORT_ANY) n->reading = 0; else return 0; v4_node_store(n, n->error_reg, code); /* raises it: P is the node's handler now */ diff --git a/v4/tests/test_fabric.c b/v4/tests/test_fabric.c index 4872511e..eda754eb 100644 --- a/v4/tests/test_fabric.c +++ b/v4/tests/test_fabric.c @@ -547,16 +547,16 @@ int main(void) /* a port with nothing on it */ fresh(); a = loaded(0); offer(5, 7); wait_into(OUT); done_mark(); wait_for_ever(); - CHECK(v4_asm_ok(&as), "a node that offers on a port nothing is wired to"); + CHECK(v4_asm_ok(&as) && v4_fabric_wire_device(&f, a, 7, &sink), "a node that offers on a port nothing is wired to (the port it ends by reading has a device that gives nothing)"); for (i = 0; i < 50; i++) (void)v4_fabric_step(&f); v4_fabric_gone_error(&f, 18); for (i = 0; i < 50; i++) (void)v4_fabric_step(&f); CHECK(v4_node_in_wait(&ND(a)->n) && ND(a)->n.faults == 0, "a bare node waits, though the fabric has an error for it"); v4_node_error_attach(&ND(a)->n, OUT + 20); v4_node_fault_attach(&ND(a)->n, 900); - (void)v4_fabric_step(&f); - CHECK(!v4_node_in_wait(&ND(a)->n) && ND(a)->n.fault_kind == V4_FAULT_RAISED && ND(a)->n.fault_addr == 18 && ND(a)->n.offers == 0, - "one that can take an error has it raised, and its offer is withdrawn"); + for (i = 0; i < 100 && ND(a)->n.mem[OUT + 2] == 0; i++) (void)v4_fabric_step(&f); /* until it has noted what it was told */ + CHECK(!v4_node_in_wait(&ND(a)->n) && ND(a)->n.faults == 0 && ND(a)->n.offers == 0 && ND(a)->n.mem[OUT] == 0 && ND(a)->n.mem[OUT + 1] == 2 * (v4_cell)V4_PORTS + 5 && ND(a)->n.mem[OUT + 2] == 1, + "one that can take an error is woken and told there is nothing on port 5: no error is raised, and its offer is withdrawn: %ld", (long)ND(a)->n.mem[OUT + 1]); /* a host with one node, whose devices always take */ fresh(); diff --git a/v4/tests/test_host_mesh.c b/v4/tests/test_host_mesh.c index 4da5ff66..c25270ca 100644 --- a/v4/tests/test_host_mesh.c +++ b/v4/tests/test_host_mesh.c @@ -306,12 +306,12 @@ int main(void) /* no room: a node that is waiting keeps what it is sent, and has room for only so much */ { - v4_cell lost = pool[1].n.mem[LOST], refused = pool[0].n.mem[REFUSED], got, not_taken; + v4_cell lost = pool[1].n.mem[LOST], refused = pool[0].n.mem[REFUSED], got, not_taken, told_of; CHECK(is_empty(tell(11, "0 GOT !")) && is_empty(tell(11, "12 AWAIT .")) && ended == 0 && pool[1].n.mem[AWAIT_FROM] == 12, "node 11 waits for an answer from 12, which is not going to send one"); CHECK(is_empty(tell(10, ": F 49 0 DO S\" HIT\" 11 SEND LOOP ; F")) && ended == 1 && ended_from == 10, "node 10 sends it 49 messages meanwhile"); CHECK(pool[1].n.mem[MQ_COUNT] > 300 && pool[1].n.mem[MQ_COUNT] <= MQ_CELLS - 36, "node 11 has kept what it has room for, and left the room that is kept for refusals: %ld cells", (long)pool[1].n.mem[MQ_COUNT]); - CHECK(pool[1].n.mem[OWED_COUNT] == 8, "it owes a refusal for each of the rest, as many as it can owe: %ld", (long)pool[1].n.mem[OWED_COUNT]); - CHECK(pool[0].n.mem[REFUSED] == refused, "and has sent none yet: it is still waiting"); + CHECK(pool[1].n.mem[OWED_COUNT] == 0 && pool[0].n.mem[REFUSED] >= refused + 8, "it owed a refusal for each of the rest, as many as it could owe at once, and paid them while it waited: node 10 was told of %ld", + (long)(pool[0].n.mem[REFUSED] - refused)); /* one from its centre ends the wait */ CHECK(is_empty(tell(10, "12 NO-ROUTE")), "node 10 forgets the way to 12"); @@ -320,9 +320,10 @@ int main(void) got = strtol(tell(11, "GOT @ ."), NULL, 10); not_taken = 49 - got; CHECK(got >= 30 && not_taken > 8, "it then did every message it had kept: %ld of the 49", (long)got); - CHECK(pool[0].n.mem[REFUSED] == refused + 8, "and sent the eight refusals it owed: node 10 was told of %ld", (long)(pool[0].n.mem[REFUSED] - refused)); - CHECK(pool[1].n.mem[LOST] == lost + not_taken + (not_taken - 8), "it counted each message it did not take, and each refusal it could not owe: %ld for %ld not taken", - (long)(pool[1].n.mem[LOST] - lost), (long)not_taken); + told_of = pool[0].n.mem[REFUSED] - refused; + CHECK(told_of >= 8 && told_of <= not_taken, "node 10 was told of %ld of them", (long)told_of); + CHECK(pool[1].n.mem[LOST] == lost + not_taken + (not_taken - told_of), "it counted each message it did not take, and each refusal it could not owe: %ld for %ld not taken, %ld told", + (long)(pool[1].n.mem[LOST] - lost), (long)not_taken, (long)told_of); /* the way to 12 is forgotten: what is sent there now is refused */ refused = pool[1].n.mem[REFUSED]; CHECK(is_empty(tell(11, ": P12 S\" 1 DROP\" 12 SEND ; P12")) && pool[1].n.mem[REFUSED] == refused + 1, "having forgotten the way to 12, what node 11 sends there goes toward its centre, which has no way either, and is refused"); @@ -330,11 +331,11 @@ int main(void) } /* a line from the console breaks a wait (MESH.md 7b.6) */ CHECK(is_empty(tell(10, "12 AWAIT .")) && ended == 0 && pool[0].n.mem[AWAIT_FROM] == 12 && waiting(hera), "node 10 waits for an answer from 12, which is not going to send one"); - CHECK(is_empty(tell(11, "20 22 + .")) && ended == 0 && pool[0].n.mem[AWAIT_FROM] == 12, "text from the console for node 11 comes to node 10 on its way: node 10 keeps it, and goes on waiting"); + CHECK(strcmp(tell(11, "20 22 + ."), "42 ") == 0 && ended == 1 && pool[0].n.mem[AWAIT_FROM] == 12, "text from the console for node 11 comes to node 10 on its way: node 10 passes it on, and goes on waiting: \"%s\"", printed); { const char *r = tell(10, "65 EMIT"); CHECK(strstr(r, "Interrupted\n") != NULL && pool[0].n.mem[AWAIT_FROM] == 0, "text from the console for node 10 itself ends its wait, with an error that says so: \"%s\"", r); - CHECK(strstr(r, "A") != NULL && strstr(r, "42 ") != NULL && ended == 3, "the line is then done as usual, and so is what was kept for node 11: \"%s\", %d ended", r, ended); + CHECK(strstr(r, "A") != NULL && ended == 2, "the line is then done as usual: \"%s\", %d ended", r, ended); CHECK(strstr(r, "Interrupted\n") < strstr(r, "A"), "the wait ends before the line that ended it is done"); } CHECK(strcmp(tell(10, "1 2 + ."), "3 ") == 0 && waiting(hera) && waiting(mid) && waiting(far), "and all three go on as before"); diff --git a/v4/tests/test_host_unit.c b/v4/tests/test_host_unit.c index ff5e38a1..76673818 100644 --- a/v4/tests/test_host_unit.c +++ b/v4/tests/test_host_unit.c @@ -276,6 +276,8 @@ static const char *tell(v4_cell node, const char *text) if (steps >= step_limit) { stuck(); return "(still running)"; } return printed; } +/* The same, answering with what has been printed: for when a node is spinning and the fabric never rests. */ +static const char *said(v4_cell node, const char *text) { (void)tell(node, text); return printed; } static int told(v4_cell node, const char *text) { return tell(node, text)[0] == 0 && ended == 1 && ended_how == V4_TEXT_COMPLETED; } /* POST's host, for the node numbered 10 (v4/include/v4/post.h): a line is @@ -525,30 +527,34 @@ int main(void) CHECK(strstr(tell(10, ": H14 S\" 1\" 14 SEND ; H14"), "Argument out of range") != NULL, "Hera herself has no way to it"); } - /* a node waits on one that is stuck and is not its neighbour; Hera kills the stuck one */ + /* two nodes each send a third text and are then stuck: the third has an answer for each that it + * cannot give, and goes on doing what others send it (MESH.md 7c). While a node spins the fabric + * never rests: said() answers with what was printed. */ step_limit = 3000000ul; - CHECK(strcmp(tell(13, ": SPIN BEGIN 0 UNTIL ; SPIN"), "(still running)") == 0, "node 13 is stuck in a loop"); - CHECK(strcmp(tell(12, ": W13 13 AWAIT . ; W13"), "(still running)") == 0 && node_numbered(12)->mem[AWAIT_FROM] == 13 && waiting(12), - "node 12, which is not wired to it, waits for its answer"); - /* while it is stuck it holds up no one (MESH.md 7c): text for it waits with Hera, who goes on */ - (void)tell(13, "1 DROP"); - CHECK(ended == 0 && v4_node_in_wait(node_numbered(10)) && !node_numbered(10)->asking && node_numbered(10)->mem[MQ_COUNT] > 0, - "text typed for the stuck node waits with Hera, offered: she sleeps in the wait, not blocked writing"); - (void)tell(11, "11 100 * ."); - CHECK(strcmp(printed, "1100 ") == 0 && ended == 1, "text typed for another node is passed on and done meanwhile: \"%s\"", printed); - (void)tell(10, "1 2 + ."); - CHECK(strcmp(printed, "3 ") == 0 && ended == 1, "and so is text for Hera herself: \"%s\"", printed); - (void)tell(10, "13 KILL"); - CHECK(node_numbered(10)->mem[MQ_COUNT] == 0, "killing it, she lets go what she kept for it"); - CHECK(node_numbered(13) == NULL && strstr(printed, "Node gone") != NULL && node_numbered(12)->mem[AWAIT_FROM] == 0 && waiting(12), - "Hera kills node 13: node 12's wait ends, with an error that says the node is gone: \"%s\"", printed); - step_limit = 30000000ul; - CHECK(strcmp(tell(12, "12 100 * ."), "1200 ") == 0 && strcmp(tell(11, "11 100 * ."), "1100 ") == 0, "and the others go on"); + CHECK(strcmp(tell(12, ": S11 S\" 1 DROP\" 11 SEND BEGIN 0 UNTIL ; S11"), "(still running)") == 0 && + strcmp(tell(13, ": S11 S\" 1 DROP\" 11 SEND BEGIN 0 UNTIL ; S11"), "(still running)") == 0, "nodes 12 and 13, either side of node 11, each send it text and are then stuck in a loop"); + CHECK(node_numbered(11)->mem[MQ_COUNT] == 18 && v4_node_in_wait(node_numbered(11)), "node 11 keeps its answer to each, offered, and sleeps: %ld cells", (long)node_numbered(11)->mem[MQ_COUNT]); + CHECK(strcmp(said(11, "11 100 * ."), "1100 ") == 0 && ended == 1 && node_numbered(11)->mem[MQ_COUNT] == 18, "text typed for node 11 is done all the same: \"%s\"", printed); + + /* a node waits on one that is stuck; text for the stuck one waits with Hera, who goes on; Hera kills it */ + CHECK(said(11, ": W13 13 AWAIT . ; W13")[0] == 0 && ended == 0 && node_numbered(11)->mem[AWAIT_FROM] == 13 && waiting(11), "node 11 waits for node 13's answer"); + { + v4_cell kept = node_numbered(10)->mem[MQ_COUNT]; + (void)tell(13, "1 DROP"); + CHECK(ended == 0 && v4_node_in_wait(node_numbered(10)) && !node_numbered(10)->asking && node_numbered(10)->mem[MQ_COUNT] > kept, + "text typed for the stuck node waits with Hera, offered: she sleeps in the wait, not blocked writing"); + } + CHECK(strcmp(said(10, "1 2 + ."), "3 ") == 0 && ended == 1, "and text for Hera herself is done meanwhile: \"%s\"", printed); + (void)tell(10, "13 KILL 65 EMIT"); + CHECK(node_numbered(13) == NULL && strstr(printed, "Node gone") != NULL && node_numbered(11)->mem[AWAIT_FROM] == 0, + "Hera kills node 13: node 11's wait ends, with an error that says the node is gone: \"%s\"", printed); + CHECK(strstr(printed, "A") != NULL && ended == 2 && node_numbered(10)->mem[MQ_COUNT] == 9 && v4_node_in_wait(node_numbered(10)), + "her line is not held by node 12, which is stuck and has to be told too: that message waits with her, offered, and what she kept for node 13 is let go: %ld cells", + (long)node_numbered(10)->mem[MQ_COUNT]); + CHECK(strcmp(said(11, "11 100 * ."), "1100 ") == 0 && strcmp(said(10, "1 2 + ."), "3 ") == 0, "and the others go on"); /* Hera's own wait, on a node that is stuck: a line from the console ends it */ - step_limit = 3000000ul; - CHECK(strcmp(tell(12, ": SPIN BEGIN 0 UNTIL ; SPIN"), "(still running)") == 0, "node 12 is stuck in a loop"); - CHECK(strcmp(tell(10, "12 AWAIT ."), "(still running)") == 0 && node_numbered(10)->mem[AWAIT_FROM] == 12 && waiting(10), "Hera waits for its answer, which will not come"); + CHECK(said(10, "12 AWAIT .")[0] == 0 && ended == 0 && node_numbered(10)->mem[AWAIT_FROM] == 12 && waiting(10), "Hera waits for node 12's answer, which will not come"); { const char *r = tell(10, "12 KILL 66 EMIT"); CHECK(strstr(r, "Interrupted\n") != NULL && strstr(r, "B") != NULL && strstr(r, "Interrupted\n") < strstr(r, "B") && ended == 2, @@ -556,8 +562,10 @@ int main(void) CHECK(node_numbered(12) == NULL && node_numbered(10)->mem[AWAIT_FROM] == 0, "the line killed the stuck node"); } step_limit = 30000000ul; + CHECK(strcmp(tell(11, "11 100 * ."), "1100 ") == 0 && strcmp(tell(10, "1 2 + ."), "3 ") == 0 && node_numbered(11)->mem[MQ_COUNT] == 0 && node_numbered(10)->mem[MQ_COUNT] == 0 && waiting(10) && waiting(11), + "the two that are left go on, and keep nothing for the nodes that are gone"); - /* Hera blocked writing to a node that is stuck: a line from the console lets her go (MESH.md 7b.7) */ + /* Hera's line must begin a message to a node that is stuck: it waits, and a line from the console ends it (MESH.md 7c.3) */ 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 && v4_node_in_wait(node_numbered(10)) && !node_numbered(10)->asking,