fix(v4.0.0): step 6e review round 2 -- only the message looked at is taken, moved or dropped; the kernel's port has no queue in a fabric; an answer nobody awaits is not a loss
- Engine: a wire keeps whether the message at its mark is the one last looked at; a node's take, move and drop of any other answer 3 and write nothing (MESH.md 7d.3). A wire cut and made again between a look and a take no longer has a NACK done as text, or 256 cells written where one was looked for. - Engine: v4_fabric_wire_kernel wires a kernel to a port with no queues; a message for it is refused at once, error 18, on a mesh as on the products. - The result of a drop is looked at; a take that does not take has the message dropped, or gone past: nothing goes round. - An answer nobody waits for is let go uncounted; (LOST) counts what should have been delivered or acted on and was not. The flood's account is exact. - Error 18 from under a word that was printing empties the data stack, as a fault does: that word's own values are not left there. - Tests: the take and drop windows cut at every step, with and without another message put; a refusal owed to a stuck node whose wire is full. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
6a7d0aa27f
commit
f1419e739c
+76
-13
@@ -165,6 +165,14 @@ static v4_cell ask(unsigned id, v4_cell wire, v4_cell a, v4_cell b, v4_cell op)
|
||||
return n->doing ? -99 : v4_node_fetch(n, P_HOW);
|
||||
}
|
||||
|
||||
/* The same for a take, a move or a drop, which are done only on the message
|
||||
* last looked at: the node looks first, as a node does. */
|
||||
static v4_cell seen(unsigned id, v4_cell wire, v4_cell a, v4_cell b, v4_cell op)
|
||||
{
|
||||
(void)ask(id, wire, 500, 0, 1);
|
||||
return ask(id, wire, a, b, op);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned a, b, c, i, steps;
|
||||
@@ -507,6 +515,7 @@ int main(void)
|
||||
LIT(P_DO); O(BANG_B); LIT(8); O(STORE_B);
|
||||
LIT(P_HAVE); O(BANG_B); O(FETCH_B); LIT(OUT + 1); O(BANG_A); O(STORE_A);
|
||||
LIT(P_A); O(BANG_B); LIT(200); O(STORE_B);
|
||||
LIT(P_DO); O(BANG_B); LIT(1); O(STORE_B); /* it looks, and then takes what it looked at */
|
||||
LIT(P_B); O(BANG_B); LIT(220); O(STORE_B);
|
||||
LIT(P_DO); O(BANG_B); LIT(2); O(STORE_B);
|
||||
LIT(P_HOW); O(BANG_B); O(FETCH_B); LIT(OUT); O(BANG_A); O(STORE_A);
|
||||
@@ -573,6 +582,7 @@ int main(void)
|
||||
for (i = 0; i < 7; i++) t[i] = ND(a)->n.mem[100 + i];
|
||||
for (i = 0; i < 8; i++) t[8 + i] = ND(a)->n.mem[110 + i];
|
||||
CHECK(v4_wire_put(f.place[a].wire[0].rx, t, t + 8) == V4_WIRE_DONE, "(a message waits)");
|
||||
f.place[a].wire[0].rx->looked = 1; /* and has been looked at */
|
||||
memcpy(snap, ND(a)->n.mem, sizeof snap);
|
||||
memcpy(&before_rx, f.place[a].wire[0].rx, sizeof before_rx);
|
||||
memcpy(&before_tx, f.place[a].wire[0].tx, sizeof before_tx);
|
||||
@@ -592,6 +602,7 @@ int main(void)
|
||||
for (i = 0; i < 7; i++) t[i] = ND(a)->n.mem[100 + i];
|
||||
for (i = 0; i < 8; i++) t[8 + i] = ND(a)->n.mem[110 + i];
|
||||
(void)v4_wire_put(f.place[a].wire[0].rx, t, t + 8);
|
||||
f.place[a].wire[0].rx->looked = 1;
|
||||
memcpy(snap, ND(a)->n.mem, sizeof snap);
|
||||
memcpy(&before_rx, f.place[a].wire[0].rx, sizeof before_rx);
|
||||
CHECK(ask(a, 0, 300, bad[k], 2) == 4 && memcmp(snap, ND(a)->n.mem, sizeof snap) == 0 && memcmp(&before_rx, f.place[a].wire[0].rx, sizeof before_rx) == 0,
|
||||
@@ -621,9 +632,9 @@ int main(void)
|
||||
CHECK(ask(a, 0, 200, 220, 7) == 0 && ask(a, 0, 200, 220, 1) == 0 && ND(a)->n.mem[200] == 200, "next: the second");
|
||||
CHECK(ask(a, 0, 200, 220, 2) == 0 && msg_is(&ND(a)->n, 200, 220, 21, 2), "take of the second");
|
||||
CHECK(ask(a, 0, 200, 220, 1) == 0 && ND(a)->n.mem[200] == 300, "the mark is at the third");
|
||||
CHECK(ask(a, 0, 200, 220, 6) == 0 && ask(a, 0, 200, 220, 4) == 0 && ask(a, 0, 200, 220, 1) == 0 && ND(a)->n.mem[200] == 300, "first and drop: the first is gone, the third is left");
|
||||
CHECK(ask(a, 0, 200, 220, 6) == 0 && seen(a, 0, 200, 220, 4) == 0 && ask(a, 0, 200, 220, 1) == 0 && ND(a)->n.mem[200] == 300, "first and drop: the first is gone, the third is left");
|
||||
CHECK(ask(a, 0, 200, 220, 7) == 3 && ask(a, 0, 200, 220, 1) == 3, "next at the end answers 3 and the mark is at no message");
|
||||
CHECK(ask(a, 0, 200, 220, 6) == 0 && ask(a, 0, 200, 220, 2) == 0 && msg_is(&ND(a)->n, 200, 220, 4, 3) && f.place[a].wire[0].rx->used == 0, "and the third is taken");
|
||||
CHECK(ask(a, 0, 200, 220, 6) == 0 && seen(a, 0, 200, 220, 2) == 0 && msg_is(&ND(a)->n, 200, 220, 4, 3) && f.place[a].wire[0].rx->used == 0, "and the third is taken");
|
||||
|
||||
/* "which wires have a message": a bit to a wire; fetching it clears arrived */
|
||||
v4_fabric_init(&f, places, 4);
|
||||
@@ -720,9 +731,9 @@ int main(void)
|
||||
for (i = 0; i < 100; i++) (void)v4_fabric_step(&f);
|
||||
CHECK(ND(a)->n.doing, "and still blocked");
|
||||
v4_wire_first(f.place[b].wire[3].rx);
|
||||
CHECK(ask(b, 3, 400, 420, 4) == 0, "the reader drops the front message (which is 263 cells)");
|
||||
CHECK(seen(b, 3, 400, 420, 4) == 0, "the reader drops the front message (which is 263 cells)");
|
||||
while (ND(a)->n.doing && f.place[b].wire[3].rx->used > 0) {
|
||||
(void)ask(b, 3, 400, 420, 4);
|
||||
(void)seen(b, 3, 400, 420, 4);
|
||||
}
|
||||
CHECK(!ND(a)->n.doing && ND(a)->n.how == 0 && f.place[a].wire[0].tx->used + 200 <= V4_WIRE_CELLS, "woken, with how it went 0");
|
||||
/* a small message in front: dropping it frees little, and the sleeper wants more than that leaves */
|
||||
@@ -742,12 +753,12 @@ int main(void)
|
||||
(void)v4_fabric_step(&f);
|
||||
CHECK(ask(a, 0, 250, 0, 9) == -99, "asleep for 250");
|
||||
v4_wire_first(f.place[b].wire[3].rx);
|
||||
CHECK(ask(b, 3, 400, 420, 4) == 0 && V4_WIRE_CELLS - f.place[a].wire[0].tx->used == 200, "the reader drops the small one: 200 are free");
|
||||
CHECK(seen(b, 3, 400, 420, 4) == 0 && V4_WIRE_CELLS - f.place[a].wire[0].tx->used == 200, "the reader drops the small one: 200 are free");
|
||||
CHECK(!ND(a)->n.doing && ND(a)->n.how == 1, "the sleeper, which wants 250, is woken, and told 1: a wire of its own has gained room, and not enough");
|
||||
CHECK(ask(a, 0, 250, 0, 9) == -99, "it asks again, and sleeps");
|
||||
for (i = 0; i < 50; i++) (void)v4_fabric_step(&f);
|
||||
CHECK(ND(a)->n.doing, "and sleeps on while nothing changes");
|
||||
CHECK(ask(b, 3, 400, 420, 4) == 0 && !ND(a)->n.doing && ND(a)->n.how == 0, "the next take gives it the room: 0");
|
||||
CHECK(seen(b, 3, 400, 420, 4) == 0 && !ND(a)->n.doing && ND(a)->n.how == 0, "the next take gives it the room: 0");
|
||||
/* woken by a message coming instead */
|
||||
v4_wire_reset(f.place[a].wire[0].tx);
|
||||
fill(f.place[a].wire[0].tx, 100);
|
||||
@@ -775,14 +786,14 @@ int main(void)
|
||||
for (i = 0; i < 100; i++) (void)v4_fabric_step(&f);
|
||||
CHECK(ND(a)->n.doing, "and it sleeps on while nothing changes");
|
||||
v4_wire_first(f.place[c].wire[2].rx);
|
||||
CHECK(ask(c, 2, 400, 420, 4) == 0, "the reader of wire 1 drops a message");
|
||||
CHECK(seen(c, 2, 400, 420, 4) == 0, "the reader of wire 1 drops a message");
|
||||
CHECK(!ND(a)->n.doing && ND(a)->n.how == 1 && f.place[a].wire[0].tx->used == V4_WIRE_CELLS, "it wakes, told 1: the wire it named has no room, but something has changed");
|
||||
CHECK(ask(a, 0, 100, 0, 10) == 1 && ask(a, 1, 100, 0, 10) == 0, "it asks which: wire 1 has the room");
|
||||
CHECK(ask(a, 0, 100, 0, 9) == -99, "asleep for room on wire 0 again: that room on wire 1 was seen");
|
||||
for (i = 0; i < 100; i++) (void)v4_fabric_step(&f);
|
||||
CHECK(ND(a)->n.doing, "and it is not woken twice for it");
|
||||
/* the room comes in the very step the node goes to sleep: the reader's take is done before the sleep is looked at */
|
||||
v4_node_store(&ND(c)->n, P_WIRE, 2); v4_node_store(&ND(c)->n, P_DO, 4);
|
||||
(void)ask(c, 2, 500, 0, 1); v4_node_store(&ND(c)->n, P_WIRE, 2); v4_node_store(&ND(c)->n, P_DO, 4);
|
||||
ND(a)->n.doing = 0;
|
||||
v4_node_store(&ND(a)->n, P_WIRE, 0); v4_node_store(&ND(a)->n, P_A, 100); v4_node_store(&ND(a)->n, P_DO, 9);
|
||||
(void)v4_fabric_step(&f);
|
||||
@@ -802,7 +813,58 @@ int main(void)
|
||||
(void)v4_node_fetch(&ND(a)->n, P_HAVE);
|
||||
(void)v4_fabric_step(&f);
|
||||
CHECK(ask(a, 0, 0, 0, 8) == -99, "asleep, for a message");
|
||||
CHECK(ask(c, 2, 400, 420, 4) == 0 && ND(a)->n.doing, "room on a wire does not wake a node that sleeps for a message only");
|
||||
CHECK(seen(c, 2, 400, 420, 4) == 0 && ND(a)->n.doing, "room on a wire does not wake a node that sleeps for a message only");
|
||||
|
||||
/* TAKE, MOVE AND DROP ARE ABOUT THE MESSAGE LAST LOOKED AT (MESH.md 7d.3). A node looks, decides, and
|
||||
* then takes: if the wire was cut and made again in between, and another message put, what is at the
|
||||
* mark is not what it looked at. Then each answers 3, no such message, and nothing is written or moved. */
|
||||
v4_fabric_init(&f, more_places, 8);
|
||||
v4_fabric_queues(&f, qpool, 8);
|
||||
a = (unsigned)v4_fabric_add(&f, &pool[0], PB);
|
||||
b = (unsigned)v4_fabric_add(&f, &pool[1], PB);
|
||||
c = (unsigned)v4_fabric_add(&f, &pool[2], PB);
|
||||
CHECK(v4_fabric_wire(&f, a, 0, b, 3) && v4_fabric_wire(&f, a, 1, c, 2), "a node between two");
|
||||
put_msg(&ND(b)->n, 100, 110, 4, 1);
|
||||
CHECK(ask(b, 3, 100, 110, 5) == 0 && ask(a, 0, 0, 0, 6) == 0, "a message of four characters comes, and the mark is at it");
|
||||
memcpy(snap, ND(a)->n.mem, sizeof snap);
|
||||
CHECK(ask(a, 0, 200, 220, 2) == 3 && ask(a, 0, 1, 0, 3) == 3 && ask(a, 0, 0, 0, 4) == 3 && f.place[a].wire[0].rx->used == 8 && memcmp(snap, ND(a)->n.mem, sizeof snap) == 0,
|
||||
"not looked at: take, move and drop each answer 3, and nothing is written or taken");
|
||||
CHECK(ask(a, 0, 200, 220, 1) == 0 && ND(a)->n.mem[206] == 4, "it is looked at: four characters");
|
||||
/* the wire is cut and made again, and a message of 1,024 characters put where the short one was */
|
||||
CHECK(v4_fabric_unwire(&f, a, 0) && v4_fabric_wire(&f, a, 0, b, 3), "the wire is cut, and made again");
|
||||
put_msg(&ND(b)->n, 100, 110, 1024, 2);
|
||||
CHECK(ask(b, 3, 100, 110, 5) == 0 && f.place[a].wire[0].rx->used == 263, "and a message of 1,024 characters is put on it");
|
||||
memcpy(snap, ND(a)->n.mem, sizeof snap);
|
||||
CHECK(ask(a, 0, 200, 220, 2) == 3 && memcmp(snap, ND(a)->n.mem, sizeof snap) == 0 && f.place[a].wire[0].rx->used == 263,
|
||||
"a take answers 3: it is not the message that was looked at. Nothing is written: not one cell, where 256 would have been");
|
||||
CHECK(ask(a, 0, 1, 0, 3) == 3 && ask(a, 0, 0, 0, 4) == 3 && f.place[a].wire[0].rx->used == 263 && f.place[a].wire[1].tx->used == 0, "nor is it moved, or dropped");
|
||||
CHECK(ask(a, 0, 200, 220, 1) == 0 && ND(a)->n.mem[206] == 1024 && ask(a, 0, 200, 220, 2) == 0 && msg_is(&ND(a)->n, 200, 220, 1024, 2), "looked at, it is taken");
|
||||
/* a look is good for one take, move or drop, and not after the mark has been moved */
|
||||
put_msg(&ND(b)->n, 100, 110, 4, 3); CHECK(ask(b, 3, 100, 110, 5) == 0, "another comes");
|
||||
put_msg(&ND(b)->n, 100, 110, 8, 4); CHECK(ask(b, 3, 100, 110, 5) == 0, "and another behind it");
|
||||
CHECK(ask(a, 0, 200, 220, 1) == 0 && ask(a, 0, 0, 0, 7) == 0 && ask(a, 0, 200, 220, 2) == 3, "looked at, then the mark moved on with next: a take answers 3");
|
||||
CHECK(ask(a, 0, 0, 0, 6) == 0 && ask(a, 0, 200, 220, 1) == 0 && ask(a, 0, 0, 0, 6) == 0 && ask(a, 0, 0, 0, 4) == 3, "looked at, then first: a drop answers 3");
|
||||
CHECK(ask(a, 0, 200, 220, 1) == 0 && ask(a, 0, 0, 0, 4) == 0 && ask(a, 0, 0, 0, 4) == 3 && f.place[a].wire[0].rx->used == 9, "looked at and dropped; the one that followed has not been looked at, and is not dropped");
|
||||
CHECK(ask(a, 0, 200, 220, 1) == 0 && ND(a)->n.mem[206] == 8 && ask(a, 0, 1, 0, 3) == 0 && f.place[a].wire[1].tx->used == 9, "looked at, it is moved");
|
||||
/* a message put behind the one looked at does not undo the look */
|
||||
put_msg(&ND(b)->n, 100, 110, 4, 5); CHECK(ask(b, 3, 100, 110, 5) == 0 && ask(a, 0, 200, 220, 1) == 0, "one comes and is looked at");
|
||||
put_msg(&ND(b)->n, 100, 110, 4, 6); CHECK(ask(b, 3, 100, 110, 5) == 0 && ask(a, 0, 200, 220, 2) == 0 && msg_is(&ND(a)->n, 200, 220, 4, 5), "another comes behind it: the first is still the one looked at, and is taken");
|
||||
|
||||
/* THE KERNEL ON A PORT has no queue: it is asked by words, and takes no messages */
|
||||
{
|
||||
static stream ks;
|
||||
static v4_device kern;
|
||||
unsigned free_before = f.queue_free;
|
||||
ks.took_n = 0; kern.take = stream_take; kern.give = 0; kern.self = &ks; kern.pending = 0;
|
||||
CHECK(v4_fabric_wire_kernel(&f, a, 5, &kern) && f.queue_free == free_before && !f.place[a].wire[5].rx && !f.place[a].wire[5].tx, "a kernel is wired to a port, and is given no queues");
|
||||
put_msg(&ND(a)->n, 100, 110, 4, 7);
|
||||
CHECK(ask(a, 5, 100, 110, 5) == 2 && ask(a, 5, 8, 0, 10) == 2 && ask(a, 5, 8, 0, 9) == 2 && ask(a, 5, 200, 220, 1) == 2 && ask(a, 5, 0, 0, 6) == 2 && !ND(a)->n.doing,
|
||||
"a message put to it, room asked of it, a sleep for room on it, a look: each answers 2 at once -- no one takes messages there");
|
||||
v4_node_store(&ND(a)->n, PB + 5, 77);
|
||||
(void)v4_fabric_step(&f);
|
||||
CHECK(!ND(a)->n.asking && ks.took_n == 1 && ks.took[0] == 77, "a word written to it is handed over as before");
|
||||
CHECK(v4_fabric_unwire(&f, a, 5) && f.queue_free == free_before, "and cutting it gives back no queue that it never had");
|
||||
}
|
||||
|
||||
/* move from one of a node's wires to another */
|
||||
v4_fabric_init(&f, more_places, 8);
|
||||
@@ -814,19 +876,20 @@ int main(void)
|
||||
put_msg(&ND(b)->n, 100, 110, 21, 4);
|
||||
ND(b)->n.mem[103] = 9;
|
||||
CHECK(ask(b, 3, 100, 110, 5) == 0 && ask(a, 0, 0, 0, 6) == 0, "a message comes on wire 0");
|
||||
CHECK(ask(a, 0, 1, 0, 3) == 0, "and is moved to wire 1");
|
||||
CHECK(seen(a, 0, 1, 0, 3) == 0, "and is moved to wire 1");
|
||||
CHECK(f.place[a].wire[0].rx->used == 0 && f.place[c].wire[2].rx->used == 7 + 6, "it is off the one and on the other");
|
||||
CHECK(ask(c, 2, 200, 220, 6) == 0 && ask(c, 2, 200, 220, 2) == 0 && ND(c)->n.mem[203] == 8 && msg_is_but(&ND(c)->n, 200, 220, 21, 4, 3),
|
||||
CHECK(ask(c, 2, 200, 220, 6) == 0 && seen(c, 2, 200, 220, 2) == 0 && ND(c)->n.mem[203] == 8 && msg_is_but(&ND(c)->n, 200, 220, 21, 4, 3),
|
||||
"and arrives whole, its fourth word one fewer");
|
||||
/* the other full: 1, and nothing moved */
|
||||
put_msg(&ND(b)->n, 100, 110, 21, 4);
|
||||
CHECK(ask(b, 3, 100, 110, 5) == 0 && ask(a, 0, 0, 0, 6) == 0, "another comes");
|
||||
fill(f.place[a].wire[1].tx, 0);
|
||||
(void)ask(a, 0, 500, 0, 1);
|
||||
memcpy(©, f.place[a].wire[0].rx, sizeof copy);
|
||||
{
|
||||
v4_wire_queue copy2;
|
||||
memcpy(©2, f.place[a].wire[1].tx, sizeof copy2);
|
||||
CHECK(ask(a, 0, 1, 0, 3) == 1, "moved to a wire with no room: 1");
|
||||
CHECK(ask(a, 0, 1, 0, 3) == 1, "looked at, and moved to a wire with no room: 1");
|
||||
CHECK(memcmp(©, f.place[a].wire[0].rx, sizeof copy) == 0 && memcmp(©2, f.place[a].wire[1].tx, sizeof copy2) == 0, "and neither wire has changed");
|
||||
}
|
||||
CHECK(ask(a, 0, 5, 0, 3) == 2 && ask(a, 0, -1, 0, 3) == 2 && ask(a, 5, 1, 0, 3) == 2, "move to a port with nothing, or from one: 2");
|
||||
@@ -872,7 +935,7 @@ int main(void)
|
||||
for (w = 0; w < 7; w++) h[w] = ND(a)->n.mem[100 + w];
|
||||
for (w = 0; w < 5; w++) t[w] = ND(a)->n.mem[110 + w];
|
||||
CHECK(v4_fabric_device_put(&f, a, 4, h, t) == 0, "the device puts a message");
|
||||
CHECK(ask(a, 4, 200, 220, 6) == 0 && ask(a, 4, 200, 220, 2) == 0 && msg_is(&ND(a)->n, 200, 220, 17, 8), "and the node takes it, whole");
|
||||
CHECK(ask(a, 4, 200, 220, 6) == 0 && seen(a, 4, 200, 220, 2) == 0 && msg_is(&ND(a)->n, 200, 220, 17, 8), "and the node takes it, whole");
|
||||
put_msg(&ND(a)->n, 100, 110, 3, 9);
|
||||
CHECK(ask(a, 4, 100, 110, 5) == 0, "the node puts one");
|
||||
memset(h, 0, sizeof h); memset(t, 0, sizeof t);
|
||||
|
||||
Reference in New Issue
Block a user