fix(v4.0.0): step 6e review round 1 -- a take that does not take does nothing; output and answers wait at a middle node; no queue on the kernel's port; a printing wait is not interrupted
- The result of every take is looked at: a wire cut between the look and the take leaves nothing acted on (the text before run again, a refusal counted, a wait ended by an old answer, a way forgotten). - A node with no room to pass on what another printed, or its word of how text ended, leaves it on the wire it came by and moves it when there is room; what is behind it for the same port waits too. Sleep for room (9) is woken by room on any of the node's wires (engine; MESH.md 7d.3). - The lone node's host keeps no queue for the kernel's port: a message to it is error 18. The step limit is counted while the node waits for room. - A text waiting for room to print is not interrupted by console text; AWAIT is, as before. (BREAK?) is gone. - A GONE is believed only by the centre's port; unawaited answers let go are counted; nothing past a message's last character goes on a wire; AWAIT sets (AWAIT-FROM) only once the stack has been tried. - test_host_depth.c: ten paths, each run works or ends in one named stack error; it fails with (ROOM) or (ROOM-SERVE) taken out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
b1d09af043
commit
6a7d0aa27f
+194
-22
@@ -46,6 +46,7 @@ static v4_cell printed_from; /* which node the last of it came from
|
||||
static int ended; /* how many messages of how text ended have come, */
|
||||
static v4_cell ended_from, ended_how; /* and the last of them */
|
||||
static unsigned ended_at; /* and how much had been printed when it came */
|
||||
static unsigned stale_out; /* output messages whose last word had anything in it past the last character */
|
||||
static int nacks; /* how many NACKs have come to the console, */
|
||||
static v4_cell nack_from, nack_about; /* and the last of them: who refused, and the node the refused message was for */
|
||||
|
||||
@@ -60,6 +61,7 @@ static unsigned console_takes(void)
|
||||
for (i = 0; i < (unsigned)hd[6] && printed_len + 1 < sizeof printed; i++) printed[printed_len++] = (char)(((v4_ucell)text[i / 4u] >> (8u * (i % 4u))) & 0xFFu);
|
||||
printed[printed_len] = 0;
|
||||
printed_from = hd[1];
|
||||
if (hd[6] % 4 != 0 && ((v4_ucell)text[hd[6] / 4] >> (8u * (unsigned)(hd[6] % 4))) != 0) stale_out++;
|
||||
} else if (hd[2] == V4_MSG_DONE) {
|
||||
ended++; ended_from = hd[1]; ended_how = text[0]; ended_at = printed_len;
|
||||
} else if (hd[2] == V4_MSG_NACK) {
|
||||
@@ -129,6 +131,17 @@ static int run(void)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* Let time pass until `when` says so; 0 if it never does. */
|
||||
static int run_until(int (*when)(void), unsigned cap)
|
||||
{
|
||||
unsigned steps;
|
||||
for (steps = 0; steps < cap; steps++) {
|
||||
if (when()) return 1;
|
||||
(void)v4_fabric_step(&f); (void)console_takes(); steps_run++;
|
||||
if (watch) watch();
|
||||
}
|
||||
return when();
|
||||
}
|
||||
/* The console sends text to a node: the message is put on the wire to the node the console is on. */
|
||||
static int put_text(v4_cell node, const char *text)
|
||||
{
|
||||
@@ -202,6 +215,22 @@ static int triangle(void)
|
||||
}
|
||||
static v4_uheat_t clock_of(unsigned id) { return pool[id].es.anticlock; }
|
||||
|
||||
/* The whole of the mesh as it stands, kept and put back: so that one moment can be gone on from many times. */
|
||||
static v4_fabric_node kept_pool[3];
|
||||
static v4_place kept_places[3];
|
||||
static v4_wire_queue kept_queues[QUEUES];
|
||||
static v4_fabric kept_f;
|
||||
static void keep(void) { memcpy(kept_pool, pool, sizeof pool); memcpy(kept_places, places, sizeof places); memcpy(kept_queues, queues, sizeof queues); kept_f = f; }
|
||||
static void put_back(void) { memcpy(pool, kept_pool, sizeof pool); memcpy(places, kept_places, sizeof places); memcpy(queues, kept_queues, sizeof queues); f = kept_f; forget(); }
|
||||
|
||||
/* what a scene waits for */
|
||||
static int far_has_one(void) { return coming_to(far, 2) && coming_to(far, 2)->used > 0; }
|
||||
static int far_has_nack(void) { return far_has_one() && coming_to(far, 2)->cell[(coming_to(far, 2)->head + 2u) % V4_WIRE_CELLS] == V4_MSG_NACK; }
|
||||
static int far_awaits_and_has_one(void) { return pool[far].n.mem[AWAIT_FROM] == 11 && far_has_one(); }
|
||||
static int mid_holds(void) { return pool[mid].n.doing && pool[mid].n.do_op == 9 && pool[mid].n.mem[H_PORT] >= 0; }
|
||||
static unsigned saw_mid_hold;
|
||||
static void watch_mid_holds(void) { if (pool[mid].n.doing && pool[mid].n.do_op == 9 && pool[mid].n.mem[H_PORT] >= 0) saw_mid_hold++; }
|
||||
|
||||
/* what a scene watches for while it runs */
|
||||
static unsigned saw_room_wait, saw_full;
|
||||
static void watch_far_waits(void)
|
||||
@@ -281,11 +310,14 @@ int main(void)
|
||||
|
||||
/* ---- no way ---- */
|
||||
nacks = 0;
|
||||
i = (unsigned)pool[hera].n.mem[LOST];
|
||||
CHECK(is_empty(tell(99, "1 2 + .")) && ended == 0, "text for a node there is no way to is not done by anyone");
|
||||
CHECK(nacks == 1 && nack_from == 10 && nack_about == 99, "the console, which sent it, is told it was refused, by the node that could not pass it on: %d from %ld about %ld",
|
||||
nacks, (long)nack_from, (long)nack_about);
|
||||
CHECK(strcmp(tell(10, "(LOST) @ ."), "1 ") == 0, "and that node has counted it");
|
||||
CHECK(pool[hera].n.mem[LOST] == (v4_cell)i + 1, "and that node has counted it");
|
||||
CHECK(strcmp(tell(11, "(LOST) @ ."), "0 ") == 0 && strcmp(tell(12, "(LOST) @ ."), "0 ") == 0, "the others have lost nothing");
|
||||
i = (unsigned)pool[hera].n.mem[LOST];
|
||||
CHECK(told(10, ": TELL2 S\" 1 DROP\" 12 SEND ; TELL2") && pool[hera].n.mem[LOST] == (v4_cell)i + 1, "an answer that comes to a node that is not waiting for it is let go, and counted");
|
||||
|
||||
/* ---- waiting ---- */
|
||||
{
|
||||
@@ -326,8 +358,10 @@ int main(void)
|
||||
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(asleep(hera) && asleep(mid) && asleep(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);
|
||||
/* each has let go, and counted, the answers to what it sent, which it did not wait for: node 10 to its
|
||||
* 12 messages and its two texts, and two from before and the message for 99; the others to 12 */
|
||||
CHECK(strcmp(tell(10, "GOT @ . (LOST) @ ."), "12 17 ") == 0 && strcmp(tell(11, "GOT @ . (LOST) @ ."), "12 12 ") == 0 && strcmp(tell(12, "GOT @ . (LOST) @ ."), "12 13 ") == 0,
|
||||
"every one of them arrived; what each has counted is the answers it did not wait for: \"%s\"", printed);
|
||||
}
|
||||
|
||||
/* ---- THE FLOOD: more than the wires hold (MESH.md 7d.6, acceptance 2) ----
|
||||
@@ -353,16 +387,11 @@ int main(void)
|
||||
lost += pool[k].n.mem[LOST];
|
||||
refused += pool[k].n.mem[REFUSED];
|
||||
}
|
||||
lost -= 1; /* the one for node 99, earlier */
|
||||
printf(" the flood: %ld sends tried, %ld on a wire, %ld refused at once; %ld done; (LOST) %ld, (REFUSED) %ld in all\n", tried, sent, tried - sent, got, lost, refused);
|
||||
CHECK(tried > sent && sent >= got && got > 0, "there was not room for all of them: some were refused at once");
|
||||
/* Every message that got on a wire and was let go on its way is counted exactly twice: once in (LOST)
|
||||
* where it was let go, and once where its NACK ended -- in (REFUSED) at the node it was for, or in
|
||||
* (LOST) if it could not go either. Every SEND refused at once is counted once, in (REFUSED). So
|
||||
* (LOST) + (REFUSED) - the refused at once is twice the messages let go; and those are the messages
|
||||
* the nodes sent each other that were not done, and answers to them. */
|
||||
CHECK((lost + refused - (tried - sent)) % 2 == 0 && lost + refused - (tried - sent) >= 2 * (sent - got),
|
||||
"every message sent was done or was counted: %ld on a wire, %ld done; (LOST) + (REFUSED) %ld, of which %ld were refused at once", sent, got, lost + refused, tried - sent);
|
||||
/* A SEND refused at once ends the word that sends, so the flood holds itself back: what got on a wire
|
||||
* is what there was room for. (LOST) counts, with what was let go on the way, every answer that
|
||||
* came to a node that did not wait for it, so it is not a count of what was lost. */
|
||||
CHECK(tried > sent && sent >= got && got > 0 && refused >= tried - sent, "there was not room for all of them: some were refused at once, and counted");
|
||||
CHECK(strcmp(tell(12, "7 8 * ."), "56 ") == 0 && printed_from == 12, "and the nodes go on as before");
|
||||
}
|
||||
|
||||
@@ -413,6 +442,10 @@ int main(void)
|
||||
c = clock_of(far);
|
||||
for (i = 0; i < 500; i++) (void)v4_fabric_step(&f);
|
||||
CHECK(asleep(far) && clock_of(far) == c, "node 12 is asleep, not going round: it owes nothing");
|
||||
/* nothing but the text goes on the wire: not what lies after it in the node's memory */
|
||||
(void)tell(12, ": S5 S\" ABCDEXYZ\" DROP 5 11 SEND ; S5");
|
||||
CHECK(coming_to(mid, 3)->used == 8 + 9 && coming_to(mid, 3)->cell[(coming_to(mid, 3)->head + 16u) % V4_WIRE_CELLS] == 'E',
|
||||
"five characters sent of eight: the last word on the wire holds the fifth and nothing else: %lx", (unsigned long)coming_to(mid, 3)->cell[(coming_to(mid, 3)->head + 16u) % V4_WIRE_CELLS]);
|
||||
CHECK(strcmp(tell(12, "7 8 * ."), "56 ") == 0 && printed_from == 12 && strcmp(tell(10, "1 2 + ."), "3 ") == 0, "and it and node 10 answer: \"%s\"", printed);
|
||||
}
|
||||
|
||||
@@ -472,7 +505,24 @@ int main(void)
|
||||
CHECK(strcmp(tell(12, "7 8 * ."), "56 ") == 0 && printed_from == 12 && asleep(far) && asleep(hera), "told another way to the console, it goes on: \"%s\"", printed);
|
||||
}
|
||||
|
||||
/* ---- a line from the console breaks a wait for room (MESH.md 7d.4) ---- */
|
||||
/* ---- NOTHING BREAKS A WAIT FOR ROOM TO PRINT (MESH.md 7d.4, ruled 2026-10-08) ----
|
||||
* A line typed ahead while a text prints more than the wire holds does not cut the printing short. */
|
||||
CHECK(triangle(), "the same made afresh");
|
||||
{
|
||||
static char want[32768];
|
||||
size_t at = 0;
|
||||
for (i = 0; i < 3000; i++) at += (size_t)snprintf(want + at, sizeof want - at, "%u ", i);
|
||||
snprintf(want + at, sizeof want - at, "56 ");
|
||||
CHECK(told(12, ": P 3000 0 DO I . LOOP ;") && told(10, ": SLOW 600000 0 DO LOOP ;"), "node 12 has a word that prints 3000 numbers, and node 10 one that takes a while");
|
||||
forget();
|
||||
saw_room_wait = 0; watch = watch_far_waits;
|
||||
CHECK(put_text(10, "SLOW") && put_text(12, "P") && put_text(12, "7 8 * .") && put_text(10, "SLOW") && put_text(10, "SLOW") && run(),
|
||||
"node 12 is typed two lines, the first of which prints more than the wire holds, while node 10 is busy");
|
||||
watch = 0;
|
||||
CHECK(saw_room_wait > 0 && strstr(printed, "Interrupted") == NULL, "node 12 slept for room to print with the second line waiting on its wire, and was not interrupted");
|
||||
CHECK(strcmp(printed, want) == 0 && ended == 5 && pool[far].n.mem[LOST] == 0, "the first text printed everything, and then the second line was done: %u characters of %u, %d ended", printed_len, (unsigned)strlen(want), ended);
|
||||
}
|
||||
/* and with a stuck node on the way, where the room never comes, text for the node is left on its wire */
|
||||
CHECK(triangle(), "the same made afresh");
|
||||
{
|
||||
CHECK(told(12, ": P 3000 0 DO I . LOOP ;") && told(12, "NO-ROUTES 2 DEFAULT-ROUTE 10 3 ROUTE"), "node 12's way to the console is by node 11 again");
|
||||
@@ -480,20 +530,131 @@ int main(void)
|
||||
(void)tell(11, ": C BEGIN 0 UNTIL ; C");
|
||||
(void)tell(12, "P");
|
||||
CHECK(ended == 0 && waits_for_room(far) && pool[far].n.mem[NODE_ERROR] == 0, "node 11 is stuck, and node 12 sleeps for room to print");
|
||||
(void)tell(11, "1 DROP");
|
||||
(void)tell(10, ": T12 S\" 1 DROP\" 12 SEND ; T12");
|
||||
CHECK(waits_for_room(far) && pool[far].n.mem[NODE_ERROR] == 0 && coming_to(far, 3)->used == 9,
|
||||
"text for node 12 from another node does not break the wait: it is left on the wire, and node 12 sleeps on: %u cells", coming_to(far, 3)->used);
|
||||
(void)tell(12, "65 EMIT");
|
||||
CHECK(pool[far].n.mem[NODE_ERROR] == 21 && waits_for_room(far) && coming_to(far, 3)->used == 18,
|
||||
"text for it from its console does: the text it was doing ends in error 21, Interrupted; the line that broke it stays on the wire: error %ld, %u cells",
|
||||
CHECK(waits_for_room(far) && pool[far].n.mem[NODE_ERROR] == 0 && pool[far].n.mem[QUIET] == 0 && coming_to(far, 3)->used == 18,
|
||||
"text for node 12, from another node and from its console, is left on the wire: its text is not ended, and it sleeps on: error %ld, %u cells",
|
||||
(long)pool[far].n.mem[NODE_ERROR], coming_to(far, 3)->used);
|
||||
(void)tell(12, "66 EMIT");
|
||||
CHECK(pool[far].n.mem[NODE_ERROR] == 21 && waits_for_room(far) && coming_to(far, 3)->used == 27 && pool[far].n.mem[OUT_PTR] <= OUT_W + OUT_CELLS,
|
||||
"its message has still to wait for the room, and is not broken a second time: MESH.md 7d.6");
|
||||
CHECK(strcmp(tell(10, "1 2 + ."), "3 ") == 0, "node 10 answers meanwhile");
|
||||
}
|
||||
|
||||
/* ---- PRINTING THROUGH A MIDDLE NODE IS NOT LOST (ruled 2026-10-08) ----
|
||||
* In the row, what node 12 prints goes by node 11 to node 10, which is busy. The wire from 11 to 10
|
||||
* fills; node 11 does not let go what it has no room to pass on: it leaves it on the wire from 12, which
|
||||
* fills in its turn, and node 12 waits. */
|
||||
CHECK(row(), "a row made afresh");
|
||||
{
|
||||
static char want[32768];
|
||||
size_t at = 0;
|
||||
for (i = 0; i < 3000; i++) at += (size_t)snprintf(want + at, sizeof want - at, "%u ", i);
|
||||
CHECK(told(12, ": P 3000 0 DO I . LOOP ;") && told(10, ": SLOW 600000 0 DO LOOP ;"), "node 12 has a word that prints 3000 numbers, and node 10 one that takes a while");
|
||||
forget();
|
||||
saw_room_wait = 0; saw_mid_hold = 0; watch = watch_mid_holds;
|
||||
CHECK(put_text(12, "P") && put_text(10, "SLOW") && put_text(10, "SLOW") && put_text(10, "SLOW") && put_text(10, "SLOW") && run(),
|
||||
"node 12 prints them while node 10 is busy with one line after another");
|
||||
watch = 0;
|
||||
CHECK(saw_mid_hold > 0, "node 11 left output on the wire it came by, for want of room, and slept for room");
|
||||
CHECK(strcmp(printed, want) == 0, "every number arrived, in order: %u characters of %u", printed_len, (unsigned)strlen(want));
|
||||
CHECK(ended == 5 && ended_at <= printed_len && pool[far].n.mem[LINE_STATUS] == 1 && pool[hera].n.mem[LOST] == 0 && pool[mid].n.mem[LOST] == 0 && pool[far].n.mem[LOST] == 0 && pool[far].n.mem[REFUSED] == 0,
|
||||
"and then how the text ended; nothing was let go anywhere: %ld %ld %ld", (long)pool[hera].n.mem[LOST], (long)pool[mid].n.mem[LOST], (long)pool[far].n.mem[LOST]);
|
||||
CHECK(asleep(hera) && asleep(mid) && asleep(far) && pool[mid].n.mem[H_PORT] == -1, "all three sleep, node 11 for a message and not for room");
|
||||
|
||||
/* the middle node removed while it holds output: node 12's text ends in an error; node 10 goes on */
|
||||
CHECK(row() && told(12, ": P 3000 0 DO I . LOOP ;") && told(10, ": SLOW 600000 0 DO LOOP ;"), "the same again");
|
||||
forget();
|
||||
CHECK(put_text(12, "P") && put_text(10, "SLOW") && put_text(10, "SLOW") && put_text(10, "SLOW") && put_text(10, "SLOW") && run_until(mid_holds, 20000000),
|
||||
"node 11 is holding output, asleep for room");
|
||||
CHECK(v4_fabric_remove(&f, mid) == &pool[1] && run(), "node 11 is removed, and the two that are left come to rest");
|
||||
CHECK(asleep(far) && pool[far].n.mem[NODE_ERROR] == 18 && pool[far].n.mem[LINE_STATUS] == 2 && pool[far].n.mem[KEEP] == -1, "node 12's text has ended in error 18, No one on that port, and it sleeps");
|
||||
CHECK(strncmp(printed, want, printed_len) == 0 && strcmp(tell(10, "1 2 + ."), "3 ") == 0 && asleep(hera), "what had arrived was in order, and node 10 goes on");
|
||||
|
||||
/* the node that prints removed while the middle node holds its output: what is on the wires arrives */
|
||||
CHECK(row() && told(12, ": P 3000 0 DO I . LOOP ;") && told(10, ": SLOW 600000 0 DO LOOP ;"), "and again");
|
||||
forget();
|
||||
CHECK(put_text(12, "P") && put_text(10, "SLOW") && put_text(10, "SLOW") && put_text(10, "SLOW") && put_text(10, "SLOW") && run_until(mid_holds, 20000000), "node 11 is holding output again");
|
||||
CHECK(v4_fabric_remove(&f, far) == &pool[2] && run(), "node 12 is removed, and the two that are left come to rest");
|
||||
CHECK(asleep(mid) && asleep(hera) && pool[mid].n.mem[H_PORT] == -1 && coming_to(hera, 2)->used == 0, "node 11 sleeps, holding nothing; nothing is left on the wire to node 10");
|
||||
CHECK(printed_len > 0 && strncmp(printed, want, printed_len) == 0 && ended >= 4, "what node 12 had printed before it went arrived, in order: %u characters", printed_len);
|
||||
CHECK(strcmp(tell(11, "20 22 + ."), "42 ") == 0 && strcmp(tell(10, "1 2 + ."), "3 ") == 0, "and nodes 10 and 11 go on");
|
||||
}
|
||||
|
||||
/* ---- A TAKE THAT DOES NOT TAKE (fix round 1, F1) ----
|
||||
* The wire is cut at every step from a message's coming to its being taken. If it was still on the wire
|
||||
* when the wire was cut it was not taken, and nothing may be done for it: not the text before it run
|
||||
* again, not a refusal counted, not a wait ended with an old answer, not a way forgotten. */
|
||||
{
|
||||
unsigned k, cut_before = 0, cut_after = 0, wrong = 0;
|
||||
CHECK(row() && told(12, "VARIABLE N : T1 1 N +! ; : T2 10 N +! ;") && told(12, "T1") && put_text(12, "T2") && run_until(far_has_one, 1000000), "text has come to node 12's wire");
|
||||
keep();
|
||||
for (k = 0; k < 200; k++) { /* text, taken by (IDLE) */
|
||||
int there;
|
||||
v4_cell lost;
|
||||
put_back();
|
||||
lost = pool[far].n.mem[LOST];
|
||||
for (i = 0; i < k; i++) { (void)v4_fabric_step(&f); (void)console_takes(); }
|
||||
there = far_has_one();
|
||||
(void)v4_fabric_unwire(&f, mid, 3);
|
||||
if (!run() || !asleep(far) || !v4_fabric_wire(&f, mid, 3, far, 2)) { wrong += 1000; break; }
|
||||
if (there) cut_before++; else { if (!cut_after && getenv("V4_MESH_STUCK")) printf(" first cut after the take: %u steps\n", k); cut_after++; }
|
||||
if (strcmp(tell(12, "N @ ."), there ? "1 " : "11 ") != 0 || pool[far].n.mem[LOST] != lost + (there ? 0 : 1)) {
|
||||
if (!wrong) printf(" cut %u steps after the text came, it %s on the wire: N is %s, %ld counted lost\n", k, there ? "still" : "no longer", printed, (long)(pool[far].n.mem[LOST] - lost));
|
||||
wrong++;
|
||||
}
|
||||
}
|
||||
CHECK(wrong == 0 && cut_before > 20 && cut_after > 0, "text: cut before it was taken (%u times) nothing was done; cut after (%u), the text was done once, and its answer counted: %u wrong", cut_before, cut_after, wrong);
|
||||
|
||||
cut_before = cut_after = wrong = 0;
|
||||
CHECK(row() && told(12, ": N77 S\" 1 DROP\" 77 SEND ;") && put_text(12, "N77") && run_until(far_has_nack, 1000000), "a NACK has come to node 12's wire");
|
||||
keep();
|
||||
for (k = 0; k < 200; k++) { /* a NACK, taken by (IDLE) */
|
||||
int there;
|
||||
v4_cell refused;
|
||||
put_back();
|
||||
refused = pool[far].n.mem[REFUSED];
|
||||
for (i = 0; i < k; i++) { (void)v4_fabric_step(&f); (void)console_takes(); }
|
||||
there = far_has_nack();
|
||||
(void)v4_fabric_unwire(&f, mid, 3);
|
||||
if (!run() || !asleep(far)) { wrong += 1000; break; }
|
||||
if (there) cut_before++; else { if (!cut_after && getenv("V4_MESH_STUCK")) printf(" first cut after the take: %u steps\n", k); cut_after++; }
|
||||
if (pool[far].n.mem[REFUSED] != refused + (there ? 0 : 1)) wrong++;
|
||||
}
|
||||
CHECK(wrong == 0 && cut_before > 20 && cut_after > 0, "a NACK: cut before it was taken (%u times) no refusal was counted; cut after (%u), one: %u wrong", cut_before, cut_after, wrong);
|
||||
|
||||
cut_before = cut_after = wrong = 0;
|
||||
CHECK(row() && told(12, ": Q S\" 1 DROP\" 11 SEND 11 AWAIT 7 + . ;") && put_text(12, "Q") && run_until(far_awaits_and_has_one, 1000000), "an answer has come to the wire of node 12, which waits for it");
|
||||
keep();
|
||||
for (k = 0; k < 200; k++) { /* an answer, taken by AWAIT */
|
||||
int there;
|
||||
put_back();
|
||||
for (i = 0; i < k; i++) { (void)v4_fabric_step(&f); (void)console_takes(); }
|
||||
there = far_has_one();
|
||||
(void)v4_fabric_unwire(&f, mid, 3);
|
||||
if (!run() || !asleep(far)) { wrong += 1000; break; }
|
||||
if (there) cut_before++; else { if (!cut_after && getenv("V4_MESH_STUCK")) printf(" first cut after the take: %u steps\n", k); cut_after++; }
|
||||
/* not taken: it waits on. Taken: the wait ended with the answer, 1, and "8 " was printed -- to a wire with no one on it. */
|
||||
if (there ? !(pool[far].n.mem[AWAIT_FROM] == 11 && pool[far].n.mem[QUIET] == 0) : !(pool[far].n.mem[AWAIT_FROM] == 0 && pool[far].n.mem[QUIET] == 1)) wrong++;
|
||||
}
|
||||
CHECK(wrong == 0 && cut_before > 5 && cut_after > 0, "an answer: cut before it was taken (%u times) the wait went on; cut after (%u), it ended: %u wrong", cut_before, cut_after, wrong);
|
||||
|
||||
cut_before = cut_after = wrong = 0;
|
||||
CHECK(row() && told(12, "55 2 ROUTE 44 2 ROUTE") && told(11, "55 12 GONE") && told(12, "55 2 ROUTE") && told(11, ": G44 44 12 GONE ;") && pool[far].n.mem[ROUTE_COUNT] == 2
|
||||
&& put_text(11, "G44") && run_until(far_has_one, 1000000), "a GONE from its centre has come to node 12's wire");
|
||||
keep();
|
||||
for (k = 0; k < 200; k++) { /* a GONE, taken by (IDLE): node 11 is node 12's centre */
|
||||
int there;
|
||||
v4_cell ways;
|
||||
put_back();
|
||||
ways = pool[far].n.mem[ROUTE_COUNT];
|
||||
for (i = 0; i < k; i++) { (void)v4_fabric_step(&f); (void)console_takes(); }
|
||||
there = far_has_one();
|
||||
(void)v4_fabric_unwire(&f, mid, 3);
|
||||
if (!run() || !asleep(far)) { wrong += 1000; break; }
|
||||
if (there) cut_before++; else { if (!cut_after && getenv("V4_MESH_STUCK")) printf(" first cut after the take: %u steps\n", k); cut_after++; }
|
||||
if (pool[far].n.mem[ROUTE_COUNT] != ways - (there ? 0 : 1)) wrong++;
|
||||
}
|
||||
CHECK(wrong == 0 && cut_before > 20 && cut_after > 0, "a GONE: cut before it was taken (%u times) no way was forgotten; cut after (%u), one: %u wrong", cut_before, cut_after, wrong);
|
||||
}
|
||||
|
||||
/* ---- Review Focus 4: THE ANSWER HAS ROOM KEPT ----
|
||||
* Node 11 sends the console 127 short messages by way of node 12, which passes them on to the wire to
|
||||
* node 10 while node 10 is busy: that wire is then full but for 8 cells. Node 10 has sent node 12 text
|
||||
@@ -508,7 +669,7 @@ int main(void)
|
||||
(void)tell(10, "G");
|
||||
watch = 0;
|
||||
CHECK(saw_full > 0, "node 12 slept for room to print with the wire to node 10 holding exactly the 8 cells kept for its answer (%u, %u)", saw_room_wait, saw_full);
|
||||
CHECK(strcmp(printed, "A1 ") == 0 && pool[far].n.mem[LOST] == 0 && pool[hera].n.mem[LOST] == 0,
|
||||
CHECK(strcmp(printed, "A1 ") == 0 && pool[far].n.mem[LOST] == 0,
|
||||
"what it printed arrived, and then how the text ended, which node 10 waited for: the answer was not refused: \"%s\"", printed);
|
||||
CHECK(asleep(hera) && asleep(mid) && asleep(far) && pool[far].n.mem[KEEP] == -1, "all three sleep, and node 12 keeps no room");
|
||||
}
|
||||
@@ -579,6 +740,16 @@ int main(void)
|
||||
(void)tell(11, "33 AWAIT .");
|
||||
CHECK(ended == 0 && told(10, "44 11 GONE") && pool[mid].n.mem[AWAIT_FROM] == 33 && asleep(mid), "a GONE from its centre about another node does not end a wait");
|
||||
}
|
||||
/* a GONE that says it is from the centre but comes by another port is not believed (MESH.md 7b.4) */
|
||||
CHECK(triangle(), "a row made afresh, with nodes 10 and 12 wired straight to each other");
|
||||
{
|
||||
v4_cell ways;
|
||||
CHECK(told(11, "44 3 ROUTE") && told(12, ": FORGE 10 (ME) ! 44 11 GONE 12 (ME) ! ;"), "node 11 has a way to 44; node 12 has a word that sends a GONE saying it is from node 10");
|
||||
ways = pool[mid].n.mem[ROUTE_COUNT];
|
||||
CHECK(told(12, "FORGE") && asleep(mid) && coming_to(mid, 3)->used == 0 && pool[mid].n.mem[ROUTE_COUNT] == ways,
|
||||
"it comes to node 11 by the wire from node 12, not by its centre's: it is not believed, and the way stays: %ld ways of %ld", (long)pool[mid].n.mem[ROUTE_COUNT], (long)ways);
|
||||
CHECK(told(10, "44 11 GONE") && pool[mid].n.mem[ROUTE_COUNT] == ways - 1, "from node 10, by its centre's port, it is");
|
||||
}
|
||||
/* interrupted: text from the console */
|
||||
CHECK(row(), "a row made afresh");
|
||||
{
|
||||
@@ -626,6 +797,7 @@ int main(void)
|
||||
* how it ended. It is looked at once an instruction word, so it is the least that was used; that 28
|
||||
* values may wait is measured in test_host_quit.c and, for passing on and refusing, in test_host_depth.c.
|
||||
* The return stack is empty when a text ends; (FINISH)'s wait for room goes seven deep on it. */
|
||||
CHECK(stale_out == 0, "no message of what a node printed carried anything past its last character: %u did", stale_out);
|
||||
printf(" between texts the nucleus used at most %u cells of the data stack and %u entries of the return stack\n", between_data, between_ret);
|
||||
CHECK(between_data <= 4 && between_ret <= 7, "between texts: four cells of the data stack, and seven return entries");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user