From 2cf37aab4f216b315222d40de4c4a6b873ac5d9e Mon Sep 17 00:00:00 2001 From: rajames Date: Thu, 8 Oct 2026 06:34:15 -0400 Subject: [PATCH] fix(v4.0.0): step 6d after its review -- no error in the middle of the messages waiting, no offer left standing Ruled 2026-10-08: A, B, C, D and the guard for a half message. Each with a scene in test_host_mesh.c that failed first. A. The words of a message after its first are written from the passes over the messages waiting by (!W): an offer and a wait for that offer only (a new engine address). A reader removed in mid-message makes no error; the rest is let go and counted. Before, the error left the messages waiting in pieces and the node going round for ever. B. A store to the wait withdraws every offer; (GATE1) and (PAY-SET) do it first. Before, text begun after a node went round without sleeping could go to the port of an older offer: text for one node was done by another. C. What a finished text printed is put with the messages waiting, as how it ended is. With no room either is let go and counted; neither is begun as a message from (FINISH) any more, where a stuck node on the way held the whole node. D. Only what a sender is owed from an earlier text -- its output, how it ended -- holds that sender's next text back; a GONE does not; and what cannot be noted holds nothing. A node's own messages keep the order they were made in. - A message half taken in when its writer is removed is let go ((MQ-MEND)), not kept as if whole. - Smaller: a refused line no longer ends a waiting text 'Interrupted'; a node's own queued messages may be passed on by 16 nodes, not 15; no value is left on the stack when a port goes in mid-refusal. make -C v4 test and sanitize at both widths, hosted-check. Co-Authored-By: Claude Opus 5.5 --- capsules/v4/nucleus-64.f18 | Bin 58488 -> 59800 bytes v4/capsule/core.v4 | 48 +++++++++++++--- v4/capsule/quit.v4 | 114 +++++++++++++++++++++++-------------- v4/include/v4/node.h | 8 +++ v4/src/fabric.c | 10 +++- v4/src/node.c | 14 +++-- v4/tests/host_map.h | 15 ++++- v4/tests/test_fabric.c | 34 +++++++++++ v4/tests/test_host_mesh.c | 108 +++++++++++++++++++++++++++++++++++ 9 files changed, 289 insertions(+), 62 deletions(-) diff --git a/capsules/v4/nucleus-64.f18 b/capsules/v4/nucleus-64.f18 index 6a9e18e8dd649c641ba069f2e82f66a121f2623a..78a565975440bdf6a27f3b767f202f3283fd43f6 100644 GIT binary patch literal 59800 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[a].node->n; - unsigned first = n->read_port == V4_PORT_ANY ? 0 : n->read_port; - unsigned last = n->read_port == V4_PORT_ANY ? V4_PORTS - 1 : n->read_port; + unsigned first; + unsigned last; unsigned k; v4_cell value; + if (n->read_port > V4_PORT_ANY) return 0; /* the wait for an offer only: it reads no port */ + first = n->read_port == V4_PORT_ANY ? 0 : n->read_port; + last = n->read_port == V4_PORT_ANY ? V4_PORTS - 1 : n->read_port; + for (k = first; k <= last; k++) { const v4_wire *w = &f->place[a].wire[k]; if (w->kind == V4_WIRE_DEVICE && w->device->give && w->device->give(w->device->self, &value)) { @@ -241,7 +245,7 @@ unsigned v4_fabric_step(v4_fabric *f) if (!awake(f, i)) continue; n = &f->place[i].node->n; if ((n->asking && f->place[i].wire[n->ask_port].kind == V4_WIRE_NONE) - || (n->reading && !n->given && n->read_port != V4_PORT_ANY && f->place[i].wire[n->read_port].kind == V4_WIRE_NONE)) + || (n->reading && !n->given && n->read_port < V4_PORTS && f->place[i].wire[n->read_port].kind == V4_WIRE_NONE)) done += (unsigned)v4_node_port_gone(n, f->gone_error); else if (v4_node_in_wait(n)) { /* an offer on a port with nothing on it */ unsigned k; diff --git a/v4/src/node.c b/v4/src/node.c index 22ad0cea..491d31ab 100644 --- a/v4/src/node.c +++ b/v4/src/node.c @@ -99,6 +99,7 @@ void v4_node_store(v4_node *n, v4_cell addr, v4_cell value) n->offers |= 1u << k; return; } + if (port == (int)V4_PORT_WAIT) { n->offers = 0; return; } /* a store to the wait: every offer is withdrawn */ if (port >= 0) { v4_node_fault(n, V4_FAULT_ADDRESS, addr); return; } /* "any", "which port" and the rest are not written to */ } /* The stack registers: a store empties the stack. -1 when not attached. */ @@ -128,7 +129,7 @@ v4_cell v4_node_fetch(v4_node *n, v4_cell addr) if (port == (int)V4_PORTS + 1) return (v4_cell)n->last_from; if (port == (int)V4_PORTS + 2) return (v4_cell)n->writers; if (port == (int)V4_PORTS + 3) return (v4_cell)n->readers; - if (port == (int)V4_PORT_WAIT) { + if (port == (int)V4_PORT_WAIT || port == (int)V4_PORT_WAIT1) { /* the wait: the word that came, or 0 for an offer taken */ if (!n->given) return 0; n->given = 0; @@ -206,18 +207,19 @@ void v4_node_port_status(v4_node *n, unsigned writers, unsigned readers) int v4_node_port_index(const v4_node *n, v4_cell addr) { - if (n->port < 0 || addr < n->port || addr > n->port + (v4_cell)V4_PORT_WAIT) return -1; + if (n->port < 0 || addr < n->port || addr > n->port + (v4_cell)V4_PORT_WAIT1) return -1; return (int)(addr - n->port); } int v4_node_read_ready(v4_node *n, v4_cell addr) { int port = v4_node_port_index(n, addr); - if (port < 0 || (port > (int)V4_PORT_ANY && port != (int)V4_PORT_WAIT)) return 1; + if (port < 0 || (port > (int)V4_PORT_ANY && port != (int)V4_PORT_WAIT && port != (int)V4_PORT_WAIT1)) return 1; if (n->given && (port >= (int)V4_PORT_ANY || (unsigned)port == n->given_port)) return 1; n->reading = 1; - n->waiting = port == (int)V4_PORT_WAIT; /* the wait is a read of any port, with offers standing */ - n->read_port = n->waiting ? V4_PORT_ANY : (unsigned)port; + n->waiting = port >= (int)V4_PORT_WAIT; /* the wait is a read of any port, with offers standing; */ + n->read_port = port == (int)V4_PORT_WAIT ? V4_PORT_ANY /* the wait for an offer only reads no port at all */ + : (unsigned)port; return 0; } @@ -288,7 +290,7 @@ int v4_node_port_gone(v4_node *n, v4_cell code) return 1; } if (n->asking) n->asking = 0; - else if (n->reading && !n->given && n->read_port != V4_PORT_ANY) n->reading = 0; + else if (n->reading && !n->given && n->read_port < V4_PORTS) n->reading = 0; else return 0; v4_node_store(n, n->error_reg, code); /* raises it: P is the node's handler now */ return 1; diff --git a/v4/tests/host_map.h b/v4/tests/host_map.h index 3cd861a7..29c0c8bd 100644 --- a/v4/tests/host_map.h +++ b/v4/tests/host_map.h @@ -73,7 +73,7 @@ #define OWED (BUF0_W - 112) /* those: for each, the node it is owed to and the node the refused message was for */ #define ACL_HOOK (BUF0_W - 6) /* the xt of the access control recheck word, or 0 */ #define LINE_STATUS (BUF0_W - 9) /* how the last line ended: 0 QUIT, 1 completed, 2 an error */ -#define PORT (BUF0_W - 144) /* the node's ports (node.h): V4_PORTS of them, then "any port", "which port", who writes, who reads, an offer for each port, and the wait: 2 * V4_PORTS + 5 cells, between the output buffer and A_FOUND. Port 0 is where its requests go. */ +#define PORT (BUF0_W - 144) /* the node's ports (node.h): V4_PORTS of them, then "any port", "which port", who writes, who reads, an offer for each port, and the two waits: 2 * V4_PORTS + 6 cells, between the output buffer and A_FOUND. Port 0 is where its requests go. */ #define CONSOLE (BUF0_W - 16) /* the node what this one prints is sent to; 0: whoever sent the text being served */ #define ROUTE_COUNT (BUF0_W - 17) /* how many entries the table of ways holds */ #define ROUTE_DEFAULT (BUF0_W - 18) /* the port address for a node not in the table, or 0: there is none */ @@ -87,8 +87,12 @@ #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 W_GONE (BUF0_W - 122) /* not 0: the port a message was being written to has nothing on it; its other words are let go */ +#define TAKING (BUF0_W - 121) /* not 0: a message is being taken in, and is only partly with the messages waiting; */ +#define T_TAIL (BUF0_W - 120) /* where they ended before it, */ +#define T_COUNT (BUF0_W - 119) /* and how many cells they took */ #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 PAY_K (BUF0_W - 31) /* 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 */ @@ -127,7 +131,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 <= PAY_K && PAY_K + (v4_cell)V4_PORTS <= BUF0_W - 115) ? 1 : -1]; +typedef char host_map_port_block_fits[(PORT + 2 * (v4_cell)V4_PORTS + 6 <= W_GONE && PAY_K + (v4_cell)V4_PORTS <= PRINT_TO) ? 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. */ @@ -205,6 +209,11 @@ static int host_load(v4_text *tx, v4_node *n, const char *const *files, unsigned 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, "(WAIT1)", PORT + (v4_cell)V4_PORT_WAIT1); + v4_text_constant(tx, "(W-GONE)", W_GONE); + v4_text_constant(tx, "(TAKING)", TAKING); + v4_text_constant(tx, "(T-TAIL)", T_TAIL); + v4_text_constant(tx, "(T-COUNT)", T_COUNT); 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); diff --git a/v4/tests/test_fabric.c b/v4/tests/test_fabric.c index a51bba88..042ff1db 100644 --- a/v4/tests/test_fabric.c +++ b/v4/tests/test_fabric.c @@ -60,6 +60,12 @@ static void wait_into(v4_cell at) LIT(PB + (v4_cell)V4_PORT_WAIT); O(BANG_B); O(FETCH_B); LIT(at); O(BANG_A); O(STORE_A); LIT(PB + (v4_cell)V4_PORTS + 1); O(BANG_B); O(FETCH_B); LIT(at + 1); O(BANG_A); O(STORE_A); } +/* the wait for an offer only */ +static void wait1_into(v4_cell at) +{ + LIT(PB + (v4_cell)V4_PORT_WAIT1); O(BANG_B); O(FETCH_B); LIT(at); O(BANG_A); O(STORE_A); + LIT(PB + (v4_cell)V4_PORTS + 1); O(BANG_B); O(FETCH_B); LIT(at + 1); O(BANG_A); O(STORE_A); +} static void done_mark(void) { LIT(1); LIT(OUT + 2); O(BANG_A); O(STORE_A); } static void count_for_ever(void) { @@ -498,6 +504,34 @@ int main(void) 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]); + /* offers are withdrawn by a store to the wait (found by the review of step 6d) */ + fresh(); + a = loaded(0); offer(0, 7); LIT(0); LIT(PB + (v4_cell)V4_PORT_WAIT); O(BANG_A); O(STORE_A); done_mark(); wait_for_ever(); + for (i = 0; i < 50; i++) (void)v4_fabric_step(&f); + CHECK(v4_asm_ok(&as) && ND(a)->n.mem[OUT + 2] == 1 && ND(a)->n.offers == 0 && ND(a)->n.faults == 0, "a node that offers and then stores to the wait has no offer left"); + + /* the wait for an offer only: a word that comes for the node does not end it */ + fresh(); + a = loaded(0); offer(0, 7); wait1_into(OUT); done_mark(); wait_for_ever(); + b = loaded(1); count_for_ever(); + c = loaded(2); LIT(PB + 0); O(BANG_B); LIT(9); O(STORE_B); wait_for_ever(); + CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 3) && v4_fabric_wire(&f, c, 0, a, 2), "a node waits for its offer only, to a node that never reads, while a third writes to it"); + for (i = 0; i < 200; i++) (void)v4_fabric_step(&f); + CHECK(v4_node_in_wait(&ND(a)->n) && ND(a)->n.mem[OUT + 2] == 0 && ND(c)->n.asking && (ND(c)->n.readers & 1u) == 0, "it goes on waiting; the writer is not served, and does not see it as reading"); + CHECK(v4_fabric_remove(&f, b) != 0, "the node offered to is removed"); + v4_fabric_gone_error(&f, 18); + v4_node_error_attach(&ND(a)->n, OUT + 20); + v4_node_fault_attach(&ND(a)->n, 900); + CHECK(v4_fabric_wire_device(&f, a, 7, &sink), "(the port it ends by reading has a device that gives nothing)"); + for (i = 0; i < 100 && ND(a)->n.mem[OUT + 2] == 0; i++) (void)v4_fabric_step(&f); + CHECK(ND(a)->n.mem[OUT + 1] == 2 * (v4_cell)V4_PORTS + 0 && ND(a)->n.faults == 0 && ND(a)->n.offers == 0 && ND(c)->n.asking, "it is told there is nothing on that port; no error is raised; the writer still waits"); + fresh(); + a = loaded(0); offer(0, 7); wait1_into(OUT); done_mark(); wait_for_ever(); + b = loaded(1); LIT(PB + 3); O(BANG_B); O(FETCH_B); LIT(OUT); O(BANG_A); O(STORE_A); wait_for_ever(); + CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 3), "the same, to a node that reads"); + (void)settle(300); + CHECK(ND(b)->n.mem[OUT] == 7 && ND(a)->n.mem[OUT + 1] == (v4_cell)V4_PORTS + 0 && ND(a)->n.mem[OUT + 2] == 1, "its offer is taken, and it is told"); + /* a host with one node, whose devices always take */ fresh(); a = loaded(0); offer(1, 21); offer(3, 23); wait_into(OUT); done_mark(); wait_for_ever(); diff --git a/v4/tests/test_host_mesh.c b/v4/tests/test_host_mesh.c index 41a823b2..bfc8082d 100644 --- a/v4/tests/test_host_mesh.c +++ b/v4/tests/test_host_mesh.c @@ -121,6 +121,28 @@ static int waiting(unsigned id) return n->reading && !n->given && n->read_port == V4_PORT_ANY; } +/* Three nodes in a row once more, 10 at the console, 11, 12: a new fabric, each + * told who it is and the way to the others. For the scenes at the end. */ +static unsigned starforth_node(unsigned k); +static void row_again(unsigned *hera, unsigned *mid, unsigned *far) +{ + unsigned i; + v4_fabric_init(&f, places, 3); + v4_fabric_gone_error(&f, V4_ERROR_NO_ONE); + *hera = starforth_node(0); *mid = starforth_node(1); *far = starforth_node(2); + (void)v4_fabric_wire_device(&f, *hera, 1, &console); + (void)v4_fabric_wire(&f, *hera, 2, *mid, 2); (void)v4_fabric_wire(&f, *mid, 3, *far, 2); + going.count = 0; going_at = 0; + step_cap = 20000000; + for (i = 0; i < 20; i++) (void)v4_fabric_step(&f); + (void)tell(0, "10 (ME) ! 1 (CONSOLE) ! 1 1 ROUTE 0 2 ROUTE"); + (void)tell(0, "11 (ME) ! 1 (CONSOLE) ! 2 DEFAULT-ROUTE 0 3 ROUTE"); + (void)tell(0, "12 (ME) ! 1 (CONSOLE) ! 2 DEFAULT-ROUTE"); + (void)tell(10, "11 2 ROUTE 12 2 ROUTE 11 2 NEIGHBOUR"); + (void)tell(11, "12 3 ROUTE 10 2 NEIGHBOUR"); + (void)tell(12, "11 2 NEIGHBOUR"); +} + int main(void) { unsigned hera, mid, far, i; @@ -487,6 +509,92 @@ int main(void) 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); + /* ==== what the review of step 6d found: each scene on a row of three, begun again ==== */ + + /* a node is removed while a message is being passed on to it */ + { + static char line[240]; + unsigned steps = 0, k; + unsigned depth; + row_again(&hera, &mid, &far); + CHECK(strcmp(tell(12, "7 8 * ."), "56 ") == 0, "three nodes in a row again"); + depth = pool[1].n.ds.depth; + memset(line, ' ', 200); memcpy(line, "1 DROP", 6); line[200] = 0; + printed_len = 0; printed[0] = 0; ended = 0; + (void)v4_message_text(&going, 12, CONSOLE_ID, V4_MSG_TEXT, line, 200); going_at = 0; + while (steps < 2000000 && !(pool[1].n.mem[MQ_COUNT] > 0 && pool[1].n.mem[MQ_COUNT] < 40 && pool[2].n.reading && pool[2].n.read_port == 2)) { (void)v4_fabric_step(&f); steps++; } + CHECK(steps < 2000000, "long text for node 12 is on its way through node 11, part written: %ld cells of it still with node 11", (long)pool[1].n.mem[MQ_COUNT]); + CHECK(v4_fabric_remove(&f, far) == &pool[2], "node 12 is removed"); + for (k = 0; k < 3000000 && v4_fabric_step(&f) != 0; k++) { } + CHECK(k < 3000000 && pool[1].n.mem[MQ_COUNT] == 0 && waiting(mid) && pool[1].n.ds.depth == depth, "node 11 comes to rest: it has let the rest go, keeps nothing, and its stack is as it was (%ld cells kept)", (long)pool[1].n.mem[MQ_COUNT]); + CHECK(strcmp(tell(11, "20 22 + ."), "42 ") == 0 && strcmp(tell(10, "1 2 + ."), "3 ") == 0, "and it and node 10 go on"); + } + + /* a node is removed while it is writing a message to its neighbour: the half that came is not kept */ + { + static char line[240]; + unsigned steps = 0, k; + row_again(&hera, &mid, &far); + memset(line, ' ', 200); memcpy(line, "1 DROP", 6); line[200] = 0; + printed_len = 0; printed[0] = 0; ended = 0; + (void)v4_message_text(&going, 12, CONSOLE_ID, V4_MSG_TEXT, line, 200); going_at = 0; + while (steps < 2000000 && !(pool[2].n.mem[MQ_COUNT] > 8 && pool[2].n.reading && pool[2].n.read_port == 2)) { (void)v4_fabric_step(&f); steps++; } + CHECK(steps < 2000000, "node 12 has taken in part of a long text from node 11: %ld cells", (long)pool[2].n.mem[MQ_COUNT]); + CHECK(v4_fabric_remove(&f, mid) == &pool[1], "node 11 is removed"); + for (k = 0; k < 3000000 && v4_fabric_step(&f) != 0; k++) { } + CHECK(k < 3000000 && pool[2].n.mem[MQ_COUNT] == 0 && waiting(far), "node 12 comes to rest, and has not kept the half: %ld cells", (long)pool[2].n.mem[MQ_COUNT]); + CHECK(v4_fabric_wire(&f, hera, 3, far, 3) && is_empty(tell(10, "12 NO-ROUTE 12 3 ROUTE")), "node 12 is wired to node 10 instead"); + (void)tell(12, "NO-ROUTES 1 3 ROUTE 10 3 ROUTE"); + CHECK(strcmp(tell(12, "7 8 * ."), "56 ") == 0, "and does what it is sent"); + } + + /* what a finished text printed, with the way to the console through a stuck node */ + row_again(&hera, &mid, &far); + CHECK(v4_fabric_wire(&f, hera, 3, far, 3) && is_empty(tell(10, "NO-ROUTES 1 1 ROUTE 11 2 ROUTE 12 3 ROUTE")) && strcmp(tell(12, "3 4 + ."), "7 ") == 0, + "node 12 is reached straight from node 10; what it prints still goes back by node 11"); + step_cap = 400000; + CHECK(strcmp(tell(11, ": ST BEGIN 0 UNTIL ; ST"), "(still running)") == 0, "node 11 is stuck in a loop"); + (void)said(10, ": P S\" 65 EMIT\" 12 SEND ; P"); + CHECK(v4_node_in_wait(&pool[2].n) && pool[2].n.mem[MQ_COUNT] > 0, "node 10 sends node 12 text that prints: what it printed, and how it ended, wait with node 12, offered, and it sleeps"); + (void)said(10, ": Q S\" 9 (REFUSED) !\" 12 SEND ; Q"); + (void)said(12, "8 (REFUSED) !"); + CHECK(pool[2].n.mem[REFUSED] == 0 && v4_node_in_wait(&pool[2].n), + "the next text from node 10, and text typed at the console for it, are kept back: what it owes each from the last has not gone (MESH.md 7c.3). It sleeps in the wait"); + { v4_cell kept = pool[2].n.mem[MQ_COUNT]; + (void)said(10, ": R S\" 7 (REFUSED) !\" 12 SEND ; R"); + CHECK(pool[2].n.mem[MQ_COUNT] > kept && v4_node_in_wait(&pool[2].n), "it is not held: it takes in what it is sent, and sleeps again"); } + CHECK(v4_fabric_remove(&f, mid) == &pool[1], "node 11 is removed"); + { unsigned k; for (k = 0; k < 3000000 && v4_fabric_step(&f) != 0; k++) { } + CHECK(k < 3000000 && pool[2].n.mem[REFUSED] == 7 && pool[2].n.mem[MQ_COUNT] == 0 && waiting(far), "what could not go is let go, the texts kept back are done in the order they came, and node 12 is at rest: %ld", (long)pool[2].n.mem[REFUSED]); } + + /* offers left standing when a node goes round to begin text */ + row_again(&hera, &mid, &far); + CHECK(v4_fabric_wire(&f, hera, 3, far, 3) && v4_fabric_wire(&f, hera, 4, far, 4), "nodes 10 and 12 are wired to each other twice over"); + (void)tell(10, "NO-ROUTES 1 1 ROUTE 11 2 ROUTE 12 3 ROUTE 77 3 ROUTE"); + (void)tell(10, ": SLOW 400000 0 DO LOOP ; : Z S\" 1 DROP\" 77 SEND SLOW ;"); + (void)tell(12, ": FWD99 S\" 67 EMIT\" 99 SEND ;"); + (void)tell(12, "NO-ROUTES 10 3 ROUTE 11 2 ROUTE 1 4 ROUTE 99 4 ROUTE"); + CHECK(strcmp(tell(12, "3 4 + ."), "7 ") == 0, "node 12's way to the console, and to 99, is by its other wire to node 10"); + step_cap = 300000; + CHECK(strcmp(tell(11, ": C S\" 1 DROP\" 12 SEND S\" FWD99\" 12 SEND BEGIN 0 UNTIL ; C"), "(still running)") == 0, "node 11 sends node 12 two texts and is stuck"); + step_cap = 30000; + (void)said(10, "Z"); + CHECK(pool[2].n.mem[OWED_COUNT] == 1, "node 10 sends 77 a message by node 12, which has no way, and is then busy: node 12 owes it a refusal, offered on its first wire"); + CHECK(v4_fabric_remove(&f, mid) == &pool[1], "node 11 is removed: node 12 lets its answer go, and begins the text it kept back"); + printed_len = 0; printed[0] = 0; printed_from = -1; + { unsigned k; for (k = 0; k < 20000000 && v4_fabric_step(&f) != 0; k++) { } + CHECK(k < 20000000, "all come to rest"); } + CHECK(strchr(printed, 'C') == NULL, "the text node 12 sent to 99 was not done by node 10: \"%s\" from %ld", printed, (long)printed_from); + CHECK(pool[0].n.mem[REFUSED] == 1 && pool[2].n.mem[OWED_COUNT] == 0, "node 10 was told its message to 77 was refused: %ld", (long)pool[0].n.mem[REFUSED]); + + /* many of a node's own messages waiting for a stuck node */ + row_again(&hera, &mid, &far); + step_cap = 300000; + CHECK(strcmp(tell(11, ": ST BEGIN 0 UNTIL ; ST"), "(still running)") == 0, "node 11 is stuck in a loop"); + { int k, good = 0; + for (k = 1; k <= 12; k++) { (void)said(10, "12 11 GONE"); if (strcmp(said(10, "1 2 + ."), "3 ") == 0) good++; } + CHECK(good == 12 && pool[0].n.mem[MQ_COUNT] == 108, "node 10 is told twelve times to tell it a node is gone, and after each still does what is typed: %d of 12, %ld cells kept", good, (long)pool[0].n.mem[MQ_COUNT]); } + printf(" %d checks, %d failures\n", checks, failures); return failures != 0; }