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
|
* 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
|
* 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
|
* 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
|
* put it on the back of a queue; fetching Have clears that for all of the
|
||||||
* node's wires.
|
* node's wires.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -30,6 +30,9 @@
|
|||||||
|
|
||||||
#define V4_WIRE_HEADER 7u /* the words of a message that are not its text */
|
#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 {
|
typedef struct {
|
||||||
v4_cell cell[V4_WIRE_CELLS]; /* the messages, one after another, going round */
|
v4_cell cell[V4_WIRE_CELLS]; /* the messages, one after another, going round */
|
||||||
unsigned head; /* where the front message begins */
|
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;
|
break;
|
||||||
case 9: /* sleep for room */
|
case 9: /* sleep for room */
|
||||||
if (!tx) { *how = V4_WIRE_NO_ONE; break; }
|
if (!tx) { *how = V4_WIRE_NO_ONE; break; }
|
||||||
if (a < 0) { *how = V4_WIRE_NOT_A_MESSAGE; break; }
|
if (a < 0 || a > (v4_cell)V4_WIRE_CELLS) { *how = V4_WIRE_NO_ROOM; break; } /* no waiting can make that room */
|
||||||
if (a <= (v4_cell)V4_WIRE_CELLS && v4_wire_room(tx, (unsigned)a) == V4_WIRE_DONE) { *how = V4_WIRE_DONE; break; }
|
if (v4_wire_room(tx, (unsigned)a) == V4_WIRE_DONE) { *how = V4_WIRE_DONE; break; }
|
||||||
if (!arrived(f, id)) return 0;
|
if (!arrived(f, id)) return 0;
|
||||||
*how = V4_WIRE_NO_ROOM;
|
*how = V4_WIRE_NO_ROOM;
|
||||||
break;
|
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;
|
if (from == to || v4_wire_room(to, n) != V4_WIRE_DONE) return V4_WIRE_NO_ROOM;
|
||||||
at = back(to, n);
|
at = back(to, n);
|
||||||
for (i = 0; i < n; i++) to->cell[slot(to, at + i)] = from->cell[slot(from, from->mark + i)];
|
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);
|
remove_marked(from);
|
||||||
return V4_WIRE_DONE;
|
return V4_WIRE_DONE;
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-2
@@ -684,6 +684,23 @@ int main(void)
|
|||||||
(void)v4_fabric_step(&f);
|
(void)v4_fabric_step(&f);
|
||||||
CHECK(!ND(a)->n.doing && ND(a)->n.how == 0, "and wakes it");
|
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 */
|
/* sleep for room */
|
||||||
v4_fabric_init(&f, places, 4);
|
v4_fabric_init(&f, places, 4);
|
||||||
v4_fabric_queues(&f, qpool, 8);
|
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");
|
"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(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(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_node_fetch(&ND(a)->n, P_HAVE);
|
||||||
(void)v4_fabric_step(&f);
|
(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");
|
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);
|
for (i = 0; i < 100; i++) (void)v4_fabric_step(&f);
|
||||||
CHECK(ND(a)->n.doing, "and still blocked");
|
CHECK(ND(a)->n.doing, "and still blocked");
|
||||||
v4_wire_first(f.place[b].wire[3].rx);
|
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(ask(b, 3, 400, 420, 4) == 0, "the reader drops the front message (which is 263 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");
|
|
||||||
while (ND(a)->n.doing && f.place[b].wire[3].rx->used > 0) {
|
while (ND(a)->n.doing && f.place[b].wire[3].rx->used > 0) {
|
||||||
(void)ask(b, 3, 400, 420, 4);
|
(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");
|
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 */
|
/* woken by a message coming instead */
|
||||||
v4_wire_reset(f.place[a].wire[0].tx);
|
v4_wire_reset(f.place[a].wire[0].tx);
|
||||||
fill(f.place[a].wire[0].tx, 100);
|
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++) { }
|
for (n = 0; n < 9 && t[n] == wt[n]; n++) { }
|
||||||
CHECK(n == 9, "and every word of its text");
|
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 */
|
/* no room in the other: 1, and neither changes */
|
||||||
v4_wire_reset(&q); v4_wire_reset(&other);
|
v4_wire_reset(&q); v4_wire_reset(&other);
|
||||||
ok = 1;
|
ok = 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user