test(v4): a second unit while the first runs; PAUSE, RESUME; GONE down the graph (MESH.md 9a.6)
test_host_unit: 125 checks. Shown to fail with the GONE hook taken out of centre.4th, and with the Hera-only check taken out of manage.c. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c88af25e1e
commit
3506747d5a
@@ -371,6 +371,15 @@ static unsigned going_from(v4_cell number, unsigned port)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 1 if the node numbered `number` has been put to sleep by the fabric (NODE-SLEEP) */
|
||||
static v4_cell hera_lost; /* Hera's (LOST) when the step 7 section begins */
|
||||
static int paused(v4_cell number)
|
||||
{
|
||||
unsigned k;
|
||||
for (k = 0; k < PLACES; k++) if (v4_fabric_node_at(&f, k) && v4_fabric_node_at(&f, k)->n.mem[ME] == number) return places[k].asleep;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned i;
|
||||
@@ -619,6 +628,96 @@ int main(void)
|
||||
"nothing was removed, and Hera goes on");
|
||||
}
|
||||
|
||||
/* ---- STEP 7 (MESH.md 9a.6): A SECOND UNIT WHILE THE FIRST RUNS; PAUSE, RESUME; GONE DOWN THE GRAPH ---- */
|
||||
step_limit = 400000000ul;
|
||||
{
|
||||
/* What Hera had let go before this section -- in the kills above -- is not this section's. */
|
||||
hera_lost = node_numbered(10)->mem[LOST];
|
||||
}
|
||||
{
|
||||
unsigned born = born_count;
|
||||
CHECK(told(10, "10 UNIT") && born_count == born + 4, "Hera births her unit again: 11 to 14 are free once more: \"%s\"", printed);
|
||||
}
|
||||
CHECK(strstr(tell(10, "11 6 6 BIRTH"), "Argument out of range") != NULL && ended_how == V4_TEXT_ERROR, "a birth of a number that is live is refused: \"%s\"", printed);
|
||||
|
||||
/* acceptance 1: it scales while running */
|
||||
spinning = 1u << 11;
|
||||
(void)tell(11, ": BUSY 3000000 0 DO LOOP ; BUSY");
|
||||
CHECK(!waiting(11) && ended == 0, "node 11 of the first unit is busy");
|
||||
{
|
||||
unsigned born = born_count, p = parity_count, k;
|
||||
const char *r = tell(10, "20 CENTRE");
|
||||
CHECK(ended == 1 && ended_how == V4_TEXT_COMPLETED && ended_from == 10, "Hera's 20 CENTRE: a second centre, and it births its own unit: \"%s\"", r);
|
||||
CHECK(born_count == born + 5 && parity_count == p + 5 && parity_number[p] == 20 && parity_number[p + 1] == 21 && parity_number[p + 4] == 24,
|
||||
"five nodes were born and reported, 20 by Hera and 21 to 24 by node 20: %u", born_count - born);
|
||||
for (k = 1; k <= 4 && parity_hash[p + k] == parity_hash[0]; k++) { }
|
||||
CHECK(k == 5, "the four outer nodes of the second unit have the dictionary hash of the first's");
|
||||
CHECK(node_numbered(20)->rom == MESH_ROM && node_numbered(24)->rom == MESH_ROM, "they carry a mesh node's ROM");
|
||||
}
|
||||
CHECK(!waiting(11), "node 11 was busy all the while");
|
||||
spinning = 0;
|
||||
CHECK(strcmp(tell(11, "11 100 * ."), "1100 ") == 0, "and goes on when its loop is done");
|
||||
for (i = 21; i <= 24; i++) {
|
||||
char text[32], want[16];
|
||||
snprintf(text, sizeof text, "%u 100 * .", i);
|
||||
snprintf(want, sizeof want, "%u ", i * 100);
|
||||
CHECK(strcmp(tell((v4_cell)i, text), want) == 0 && printed_from == (v4_cell)i, "text for node %u goes by Hera and node 20, and what it prints comes back: \"%s\"", i, printed);
|
||||
}
|
||||
CHECK(strstr(tell(12, ": X22 S\" 7 6 * .\" 22 SEND 22 AWAIT . ; X22"), "42 ") != NULL && strstr(printed, "1 ") != NULL && ended_how == V4_TEXT_COMPLETED,
|
||||
"node 12 of the first unit sends node 22 of the second text and waits for it: it is done, and its answer comes back: \"%s\"", printed);
|
||||
CHECK(strcmp(tell(23, ": T S\" 65 EMIT\" 24 SEND ; T"), "A") == 0 && printed_from == 24, "the second unit's nodes talk across their own square: \"%s\"", printed);
|
||||
|
||||
/* acceptance 2: Hera manages */
|
||||
CHECK(waiting(10) && waiting(11) && waiting(12) && waiting(13) && waiting(14) && waiting(20) && waiting(21) && waiting(22) && waiting(23) && waiting(24), "all ten are waiting");
|
||||
{
|
||||
v4_uheat_t c[10];
|
||||
static const v4_cell who[10] = { 10, 11, 12, 13, 14, 20, 21, 22, 23, 24 };
|
||||
for (i = 0; i < 10; i++) c[i] = clock_of(who[i]);
|
||||
for (i = 0; i < 5000; i++) (void)v4_fabric_step(&f);
|
||||
for (i = 0; i < 10 && clock_of(who[i]) == c[i]; i++) { }
|
||||
CHECK(i == 10, "and none executes anything while it waits: the anti-clocks do not move");
|
||||
}
|
||||
spinning = 1u << 13;
|
||||
(void)tell(13, ": LONG 2000000 0 DO LOOP ; LONG");
|
||||
CHECK(!waiting(13) && ended == 0, "node 13 is in a long loop");
|
||||
CHECK(told(10, "13 PAUSE") && paused(13), "Hera puts it to sleep, by its number");
|
||||
{
|
||||
v4_uheat_t c = clock_of(13);
|
||||
for (i = 0; i < 100000; i++) (void)v4_fabric_step(&f);
|
||||
CHECK(clock_of(13) == c, "asleep, it executes nothing");
|
||||
CHECK(told(11, ": T13 S\" 5 .\" 13 SEND ; T13") && going_from(11, 4) > 0, "text node 11 sends it waits on the wire to it: %u cells", going_from(11, 4));
|
||||
CHECK(told(10, "13 RESUME") && !paused(13), "Hera wakes it");
|
||||
spinning = 0;
|
||||
CHECK(strstr(tell(10, "1 DROP"), "5 ") != NULL && clock_of(13) != c && waiting(13), "its loop goes on to its end, and then the text is done: \"%s\"", printed);
|
||||
}
|
||||
CHECK(strstr(tell(10, "99 PAUSE"), "PAUSE: no such node") != NULL && strstr(tell(10, "10 RESUME"), "RESUME: no such node") != NULL, "PAUSE and RESUME of what is not a node, or of Hera, say so");
|
||||
|
||||
/* acceptance 4: GONE down the graph */
|
||||
(void)tell(21, ": W12 12 AWAIT . ; W12");
|
||||
CHECK(ended == 0 && node_numbered(21)->mem[AWAIT_FROM] == 12 && waiting(21), "node 21 of the second unit waits on node 12 of the first");
|
||||
(void)tell(10, "12 KILL");
|
||||
CHECK(node_numbered(12) == NULL && strstr(printed, "Node gone") != NULL && node_numbered(21)->mem[AWAIT_FROM] == 0,
|
||||
"Hera kills node 12: her GONE goes to node 20, which tells its own, and node 21's wait ends: \"%s\"", printed);
|
||||
{
|
||||
v4_cell ways = node_numbered(22)->mem[ROUTE_COUNT];
|
||||
CHECK(told(22, "88 3 ROUTE") && told(21, "88 22 GONE") && node_numbered(22)->mem[ROUTE_COUNT] == ways + 1,
|
||||
"a GONE from node 21, which is not node 22's centre, is not believed");
|
||||
}
|
||||
|
||||
/* acceptance 1, the end: the second unit is removed and the first carries on */
|
||||
{
|
||||
unsigned born = born_count;
|
||||
CHECK(told(10, "20 UNIT-KILL") && node_numbered(20) == NULL && node_numbered(21) == NULL && node_numbered(24) == NULL && born_count == born,
|
||||
"Hera's 20 UNIT-KILL: node 20's children and then node 20 are removed: \"%s\"", printed);
|
||||
CHECK(strcmp(tell(10, "20 NODE-PLACE . 21 NODE-PLACE . 24 NODE-PLACE ."), "-1 -1 -1 ") == 0, "the kernel has none of them: \"%s\"", printed);
|
||||
CHECK(strstr(tell(10, ": H21 S\" 1\" 21 SEND ; H21"), "Argument out of range") != NULL, "Hera has no way to them");
|
||||
}
|
||||
CHECK(strcmp(tell(10, "1 2 + ."), "3 ") == 0 && strcmp(tell(11, "1 2 + ."), "3 ") == 0 && strcmp(tell(13, "1 2 + ."), "3 ") == 0
|
||||
&& strcmp(tell(14, "1 2 + ."), "3 ") == 0, "and the first unit carries on: every node answers");
|
||||
CHECK(node_numbered(10)->mem[LOST] == hera_lost && node_numbered(11)->mem[LOST] == 0 && node_numbered(13)->mem[LOST] == 0 && node_numbered(14)->mem[LOST] == 0
|
||||
&& waiting(10) && waiting(11) && waiting(13) && waiting(14), "nothing was let go in all of this, and all wait again: Hera %ld (%ld before)",
|
||||
(long)node_numbered(10)->mem[LOST], (long)hera_lost);
|
||||
|
||||
printf(" %d checks, %d failures\n", checks, failures);
|
||||
return failures != 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user