fix(v4.0.0): wire review round 1 -- tests for the wake-up order and for waking only on enough room; no overflow moving a message; sleep for impossible room answers at once
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
d5cd64605d
commit
83694b18be
@@ -148,7 +148,7 @@ void v4_fabric_wake(v4_fabric *f, unsigned id);
|
||||
* Sleep (8) and sleep for room (9) are the two that wait: the node stays
|
||||
* blocked, executing nothing, until a message has come to one of its wires
|
||||
* since it last fetched which wires have one -- or, for 9, until its wire
|
||||
* has the room. A message has "come" when a put or a move or a device put
|
||||
* has the room (a wire that can never have the room answers 1 at once). A message has "come" when a put or a move or a device put
|
||||
* put it on the back of a queue; fetching Have clears that for all of the
|
||||
* node's wires.
|
||||
*
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
|
||||
#define V4_WIRE_HEADER 7u /* the words of a message that are not its text */
|
||||
|
||||
/* a wire must be able to hold the largest message there is: 1,024 characters */
|
||||
typedef char v4_wire_holds_a_message[(V4_WIRE_CELLS >= 7 + 1024 / 4) ? 1 : -1];
|
||||
|
||||
typedef struct {
|
||||
v4_cell cell[V4_WIRE_CELLS]; /* the messages, one after another, going round */
|
||||
unsigned head; /* where the front message begins */
|
||||
|
||||
+2
-2
@@ -370,8 +370,8 @@ static int operate(v4_fabric *f, unsigned id, v4_cell *how)
|
||||
break;
|
||||
case 9: /* sleep for room */
|
||||
if (!tx) { *how = V4_WIRE_NO_ONE; break; }
|
||||
if (a < 0) { *how = V4_WIRE_NOT_A_MESSAGE; break; }
|
||||
if (a <= (v4_cell)V4_WIRE_CELLS && v4_wire_room(tx, (unsigned)a) == V4_WIRE_DONE) { *how = V4_WIRE_DONE; break; }
|
||||
if (a < 0 || a > (v4_cell)V4_WIRE_CELLS) { *how = V4_WIRE_NO_ROOM; break; } /* no waiting can make that room */
|
||||
if (v4_wire_room(tx, (unsigned)a) == V4_WIRE_DONE) { *how = V4_WIRE_DONE; break; }
|
||||
if (!arrived(f, id)) return 0;
|
||||
*how = V4_WIRE_NO_ROOM;
|
||||
break;
|
||||
|
||||
+1
-1
@@ -118,7 +118,7 @@ int v4_wire_move(v4_wire_queue *from, v4_wire_queue *to)
|
||||
if (from == to || v4_wire_room(to, n) != V4_WIRE_DONE) return V4_WIRE_NO_ROOM;
|
||||
at = back(to, n);
|
||||
for (i = 0; i < n; i++) to->cell[slot(to, at + i)] = from->cell[slot(from, from->mark + i)];
|
||||
to->cell[slot(to, at + 3u)] = (v4_cell)(from->cell[slot(from, from->mark + 3u)] - 1);
|
||||
to->cell[slot(to, at + 3u)] = (v4_cell)((v4_ucell)from->cell[slot(from, from->mark + 3u)] - 1u); /* in the unsigned type: no overflow at the least cell */
|
||||
remove_marked(from);
|
||||
return V4_WIRE_DONE;
|
||||
}
|
||||
|
||||
+41
-2
@@ -684,6 +684,23 @@ int main(void)
|
||||
(void)v4_fabric_step(&f);
|
||||
CHECK(!ND(a)->n.doing && ND(a)->n.how == 0, "and wakes it");
|
||||
|
||||
/* a message put in the same engine step as the node's fetch of "which wires" is not lost: the next sleep does not block */
|
||||
v4_fabric_init(&f, places, 4);
|
||||
v4_fabric_queues(&f, qpool, 8);
|
||||
a = (unsigned)v4_fabric_add(&f, &pool[0], PB);
|
||||
b = (unsigned)v4_fabric_add(&f, &pool[1], PB);
|
||||
CHECK(v4_fabric_wire(&f, a, 0, b, 3), "two nodes for the same-step put");
|
||||
(void)v4_node_fetch(&ND(a)->n, P_HAVE); /* the fetch is seen in the step's execute phase ... */
|
||||
put_msg(&ND(b)->n, 100, 110, 3, 1);
|
||||
v4_node_store(&ND(b)->n, P_WIRE, 3);
|
||||
v4_node_store(&ND(b)->n, P_A, 100);
|
||||
v4_node_store(&ND(b)->n, P_B, 110);
|
||||
v4_node_store(&ND(b)->n, P_DO, 5); /* ... and the put is done in the same step's operations */
|
||||
(void)v4_fabric_step(&f);
|
||||
CHECK(!ND(b)->n.doing && ND(b)->n.how == 0 && f.place[a].wire[0].rx->used == 8 && f.place[a].wire[0].rx->arrived != 0,
|
||||
"the put and the fetch were in one step: the message is on the wire and counts as arrived");
|
||||
CHECK(ask(a, 0, 0, 0, 8) == 0, "so the sleep that follows does not block");
|
||||
|
||||
/* sleep for room */
|
||||
v4_fabric_init(&f, places, 4);
|
||||
v4_fabric_queues(&f, qpool, 8);
|
||||
@@ -695,18 +712,40 @@ int main(void)
|
||||
"room, with 100 cells free: for 50 and for 100, not for 101");
|
||||
CHECK(ask(a, 5, 10, 0, 10) == 2 && ask(a, 0, -1, 0, 10) == 4, "room on a port with nothing is 2, for -1 cells 4");
|
||||
CHECK(f.place[a].wire[0].tx->used == V4_WIRE_CELLS - 100 && !ND(a)->n.doing, "and it changes nothing");
|
||||
CHECK(ask(a, 0, V4_WIRE_CELLS + 1, 0, 9) == 1 && ask(a, 0, 100000, 0, 9) == 1 && ask(a, 0, -1, 0, 9) == 1 && !ND(a)->n.doing,
|
||||
"sleep for more room than the wire can ever have answers 1 at once, not blocked");
|
||||
(void)v4_node_fetch(&ND(a)->n, P_HAVE);
|
||||
(void)v4_fabric_step(&f);
|
||||
CHECK(ask(a, 0, 200, 0, 9) == -99 && ND(a)->n.doing, "sleep for 200 cells with 100 free: blocked");
|
||||
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 one message (which takes a few cells)");
|
||||
CHECK(ND(a)->n.doing || f.place[a].wire[0].tx->used + 200 <= V4_WIRE_CELLS, "woken when the reader has taken enough, not before");
|
||||
CHECK(ask(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);
|
||||
}
|
||||
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 */
|
||||
v4_wire_reset(f.place[a].wire[0].tx);
|
||||
v4_wire_reset(f.place[b].wire[3].rx);
|
||||
{
|
||||
v4_cell hh[7] = { 1, 2, 3, 4, 5, 6, 12 };
|
||||
static v4_cell tt[V4_WIRE_CELLS];
|
||||
(void)v4_wire_put(f.place[a].wire[0].tx, hh, tt); /* 10 cells */
|
||||
hh[6] = 1024;
|
||||
for (i = 0; i < 3; i++) (void)v4_wire_put(f.place[a].wire[0].tx, hh, tt);
|
||||
hh[6] = 4 * (35 - 7);
|
||||
(void)v4_wire_put(f.place[a].wire[0].tx, hh, tt); /* 35 cells: 190 are free */
|
||||
}
|
||||
CHECK(V4_WIRE_CELLS - f.place[a].wire[0].tx->used == 190, "a wire with 190 free and a small message in front");
|
||||
(void)v4_node_fetch(&ND(a)->n, P_HAVE);
|
||||
(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");
|
||||
for (i = 0; i < 50; i++) (void)v4_fabric_step(&f);
|
||||
CHECK(ND(a)->n.doing, "and the sleeper, which wants 250, is not woken by a take that did not give it room");
|
||||
CHECK(ask(b, 3, 400, 420, 4) == 0 && !ND(a)->n.doing && ND(a)->n.how == 0, "the next take does, with 0");
|
||||
/* woken by a message coming instead */
|
||||
v4_wire_reset(f.place[a].wire[0].tx);
|
||||
fill(f.place[a].wire[0].tx, 100);
|
||||
|
||||
@@ -235,6 +235,26 @@ int main(void)
|
||||
for (n = 0; n < 9 && t[n] == wt[n]; n++) { }
|
||||
CHECK(n == 9, "and every word of its text");
|
||||
}
|
||||
/* the fourth word is one fewer for every value, the most negative cell included (no overflow) */
|
||||
{
|
||||
const v4_cell least = (v4_cell)((v4_ucell)1 << (V4_CELL_BITS - 1));
|
||||
const v4_cell most = (v4_cell)(((v4_ucell)1 << (V4_CELL_BITS - 1)) - 1u);
|
||||
static const int which[3] = { 0, 1, 2 };
|
||||
unsigned m;
|
||||
for (m = 0; m < 3; m++) {
|
||||
v4_wire_reset(&q); v4_wire_reset(&other);
|
||||
make(h, t, 8, 5);
|
||||
h[3] = which[m] == 0 ? least : which[m] == 1 ? 0 : most;
|
||||
CHECK(v4_wire_put(&q, h, t) == V4_WIRE_DONE, "(a message whose fourth word is an extreme)");
|
||||
v4_wire_first(&q);
|
||||
CHECK(v4_wire_move(&q, &other) == V4_WIRE_DONE, "moved");
|
||||
v4_wire_first(&other);
|
||||
CHECK(v4_wire_take(&other, h2, t2, V4_WIRE_CELLS) == V4_WIRE_DONE, "and taken");
|
||||
CHECK(h2[3] == (which[m] == 0 ? most : which[m] == 1 ? (v4_cell)-1 : (v4_cell)(most - 1)),
|
||||
"its fourth word is one fewer, wrapping at the least cell: %ld", (long)h2[3]);
|
||||
}
|
||||
}
|
||||
|
||||
/* no room in the other: 1, and neither changes */
|
||||
v4_wire_reset(&q); v4_wire_reset(&other);
|
||||
ok = 1;
|
||||
|
||||
Reference in New Issue
Block a user