feat(v4.0.0): step 6e -- a node removed at any step leaves the rest at rest; written up

test_host_mesh.c, 220 checks: three exchanges on the row of three -- text
from the console for node 12 with what it prints and how it ended; node 11
SENDing node 12 text and waiting for its answer; a message node 12 has no
way for and its NACK to node 10 -- are each played once for every engine
step they take with node 11 removed at that step, and again with node 12:
17,642 removals at 64 bits.  Every node left comes to rest asleep, blocked
at no port and in no operation, and answers.  What is typed is a word
defined beforehand, so that the steps are the exchange's and not the
dictionary being searched.

Removed from the engine, nothing using them: v4_fabric_interrupt_error, a
device's pending hook, v4_node_words_since_look, V4_ERROR_INTERRUPTED.

MESH.md: 4.1's table has the addresses after the ports; 7a and 7b say what
of them still holds; 7b.7's limit is closed; step 6e is written up.
v4/README.md likewise.

make -C v4 test and sanitize at both widths, hosted-check, lint.  Three
bare-metal boots with the typed session and a loop printing 400 numbers:
logs/20261013-165124 (amd64), -165428 (aarch64), -165818 (riscv64).  POST
538 of 538, word_count=317, dict_hash=0x0951d7e02e251554 on all six, and
the three sessions are the same character for character.  The boots were
built with the working tree's uncommitted change to kernel/Makefile that
adds the ISA to the kernel's version line; nothing else differs from this
commit.

The plan's final review is not done yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-13 17:47:05 -04:00
co-authored by Claude Opus 5.5
parent ab96a9f2be
commit 06da5700bc
17 changed files with 893 additions and 142 deletions
+17 -9
View File
@@ -115,13 +115,9 @@ steps 8 and 9.
**Finding the way** (`MESH.md` step 4) is built: a node has a table of
which port leads toward which node (`ROUTE`, `DEFAULT-ROUTE`, `NO-ROUTES`),
passes on a message that is not for it, and `SEND`s text to another node;
`v4/tests/test_host_mesh.c` runs three StarForth nodes in a row. A node
looks before it begins a message (`MESH.md` section 7a): it takes in what
its neighbours are waiting to write to it, keeps those messages until it
has nothing else to do, and writes only to a neighbour that is waiting to
read -- or, of two neighbours, the one with the lower number may wait.
`NEIGHBOUR ( node port -- )` tells a node who is on each port. A node with
no room for one more message lets it go and counts it in `(LOST)`.
`v4/tests/test_host_mesh.c` runs three StarForth nodes in a row.
`NEIGHBOUR ( node port -- )` tells a node who is on each port. What a node
cannot take or pass on it lets go and counts in `(LOST)`.
**Five nodes from nothing** (`MESH.md` step 5) is built and proven in the
fabric under test: Hera asks whoever holds the fabric for a node
@@ -141,8 +137,20 @@ sixteenth to pass it on, sends a NACK to whoever waits on it; `(REFUSED)`
counts them. `AWAIT` ends in an error if the answer is not going to come:
"Message refused", "Node gone", or "Interrupted" when a line is typed at
the console. `n KILL` on Hera removes node n and tells every other node it
is gone; a node believes that only from its centre. A stuck node can hold
up its neighbours until it is killed: `MESH.md` 7b.7 says how.
is gone; a node believes that only from its centre.
**Messages on the wire** (`MESH.md` 7d, step 6e). A node that is stuck
holds up no other node. The fabric keeps a queue of whole messages each
way on every wire (`v4/src/wire.c`, 1,024 cells), and a node asks it,
through six addresses after its ports, to look at, take, move, drop or
put a whole message: each is one engine step, all of it or none. A node
holds nothing in transit. `SEND`, an answer, a NACK and a GONE go at once
or are refused at once; only what a text prints waits for room, so that
output is not lost. A node with nothing to do sleeps until a message
comes. A node removed at any step of an exchange leaves the others at
rest and answering (`v4/tests/test_host_mesh.c`). What it costs is in
`MESH.md` 7d.6: a burst beyond what a wire holds is refused, and text for
a node that is stuck fills its wire and is refused from then on.
**Blocks** (`MESH.md` step 6). The block words are the kernel's, as they
are for a v3 VM: `BLOCK`, `BUFFER`, `UPDATE`, `SAVE-BUFFERS` and
-15
View File
@@ -27,7 +27,6 @@ typedef struct {
int (*take)(void *self, v4_cell value); /* the node wrote `value`: 1 if it is taken, 0 if not yet */
int (*give)(void *self, v4_cell *value); /* the node is reading: 1 with a word in *value, 0 if not yet */
void *self;
int (*pending)(void *self); /* 1 if it has a word to give that has not been asked for; may be 0: it never says */
} v4_device;
/* One end of a wire. */
@@ -61,7 +60,6 @@ typedef struct {
unsigned queue_count, queue_free; /* how many, and how many are not on a wire */
unsigned queue_first; /* the first that is not, and the index plus one; 0: none. Each links to the next by its `head`. */
v4_cell gone_error; /* see v4_fabric_gone_error; 0: none */
v4_cell interrupt_error; /* see v4_fabric_interrupt_error; 0: none */
} v4_fabric;
/* An empty fabric with room for `capacity` nodes, in `places`. */
@@ -99,19 +97,6 @@ int v4_fabric_device_take(v4_fabric *f, unsigned node, unsigned port, v4_cell *h
* is how a fabric begins, nothing is raised. */
void v4_fabric_gone_error(v4_fabric *f, v4_cell code);
/* A NODE BLOCKED WRITING TO A NODE THAT DOES NOT READ. Of two neighbours
* one may write to the other without looking (docs/v4.0.0/MESH.md 7a), and
* is then blocked until the other reads; if the other never does, it is
* blocked for ever, and if it is the node the console is on, nothing can be
* typed to it again. So: when a node that can take an error is blocked
* writing to another node, on the first word of a message (node.h,
* v4_node_words_since_look: nothing of the message has gone), and a device
* on one of its own ports says it has something pending for it, the error
* `code` is raised on the node: it gives up that message and goes on, to
* read what the device has. Only a device with a `pending` function can
* do this. With `code` 0, which is how a fabric begins, it never happens. */
void v4_fabric_interrupt_error(v4_fabric *f, v4_cell code);
/* More room: `places`, of `capacity` no less than before, takes over; every
* node keeps its number and its wiring. */
void v4_fabric_grow(v4_fabric *f, v4_place *places, unsigned capacity);
-5
View File
@@ -65,11 +65,6 @@ typedef struct {
* port". */
#define V4_ERROR_NO_ONE 18
/* The nucleus's error for a node let go of a message it was blocked on the
* first word of, because its console has a line for it (fabric.h,
* v4_fabric_interrupt_error): "Interrupted". */
#define V4_ERROR_INTERRUPTED 21
/* The description of the nucleus built from v4/capsule (the generated file
* defines it). */
extern const v4_image v4_capsule_image;
-8
View File
@@ -120,7 +120,6 @@ typedef struct {
unsigned last_from; /* the port the last read from "any" took its word from */
unsigned writers; /* bit k: the neighbour on port k is blocked writing to this node */
unsigned readers; /* bit k: the neighbour on port k is blocked reading from this node */
unsigned since_look; /* words taken from this node since it last fetched either of those */
/* Whole messages on the wires (MESH.md 7d.3). See v4_node_port_attach. */
unsigned wire; /* the port that A, B and Do are about; V4_PORTS if what was stored is not a port */
@@ -262,13 +261,6 @@ int v4_node_doing(const v4_node *n);
void v4_node_done(v4_node *n, v4_cell how);
void v4_node_have(v4_node *n, unsigned mask);
/* How many words the node has had taken since it last looked at its
* neighbours (a fetch of either of the two status addresses). A node that
* looks before it begins a message (MESH.md 7a) and is blocked writing with
* this at 0 is blocked on the first word of the message: nothing of it has
* gone. */
unsigned v4_node_words_since_look(const v4_node *n);
/* THERE IS NO ONE ON THE PORT the node is blocked at -- writing to it, or
* reading from that one port -- and there will not be. A node that can
* take an error (it has an error register and a fault table: node.h,
-24
View File
@@ -25,7 +25,6 @@ void v4_fabric_init(v4_fabric *f, v4_place *places, unsigned capacity)
f->queue_free = 0;
f->queue_first = 0;
f->gone_error = 0;
f->interrupt_error = 0;
for (i = 0; i < capacity; i++) clear_place(&places[i]);
}
@@ -34,11 +33,6 @@ void v4_fabric_gone_error(v4_fabric *f, v4_cell code)
f->gone_error = code;
}
void v4_fabric_interrupt_error(v4_fabric *f, v4_cell code)
{
f->interrupt_error = code;
}
void v4_fabric_grow(v4_fabric *f, v4_place *places, unsigned capacity)
{
unsigned i;
@@ -463,24 +457,6 @@ unsigned v4_fabric_step(v4_fabric *f)
for (i = 0; i < f->capacity; i++)
if (awake(f, i) && f->place[i].node->n.reading && !f->place[i].node->n.given) done += hand_over_read(f, i);
/* a node blocked on the first word of a message to a node that is not
* reading, while a device of its own has something for it */
if (f->interrupt_error != 0)
for (i = 0; i < f->capacity; i++) {
v4_node *n;
unsigned k;
if (!awake(f, i)) continue;
n = &f->place[i].node->n;
if (!n->asking || f->place[i].wire[n->ask_port].kind != V4_WIRE_NODE || v4_node_words_since_look(n) != 0) continue;
for (k = 0; k < V4_PORTS; k++) {
const v4_wire *w = &f->place[i].wire[k];
if (w->kind == V4_WIRE_DEVICE && w->device->pending && w->device->pending(w->device->self)) {
done += (unsigned)v4_node_port_gone(n, f->interrupt_error);
break;
}
}
}
/* a node blocked at one port that nothing is wired to */
if (f->gone_error != 0)
for (i = 0; i < f->capacity; i++) {
+2 -9
View File
@@ -124,8 +124,8 @@ v4_cell v4_node_fetch(v4_node *n, v4_cell addr)
{
int port = v4_node_port_index(n, addr);
if (port == (int)V4_PORTS + 1) return (v4_cell)n->last_from;
if (port == (int)V4_PORTS + 2) { n->since_look = 0; return (v4_cell)n->writers; }
if (port == (int)V4_PORTS + 3) { n->since_look = 0; return (v4_cell)n->readers; }
if (port == (int)V4_PORTS + 2) return (v4_cell)n->writers;
if (port == (int)V4_PORTS + 3) return (v4_cell)n->readers;
if (port == (int)V4_PORT_WIRE) return (v4_cell)n->wire;
if (port == (int)V4_PORT_A) return n->wire_a;
if (port == (int)V4_PORT_B) return n->wire_b;
@@ -189,7 +189,6 @@ void v4_node_port_attach(v4_node *n, v4_cell base)
n->last_from = 0;
n->writers = 0;
n->readers = 0;
n->since_look = 0;
n->wire = 0;
n->wire_a = 0;
n->wire_b = 0;
@@ -240,7 +239,6 @@ void v4_node_born(v4_node *n, v4_cell base)
void v4_node_port_served(v4_node *n)
{
n->asking = 0;
n->since_look++;
}
int v4_node_doing(const v4_node *n)
@@ -259,11 +257,6 @@ void v4_node_have(v4_node *n, unsigned mask)
n->have = mask;
}
unsigned v4_node_words_since_look(const v4_node *n)
{
return n->since_look;
}
int v4_node_port_gone(v4_node *n, v4_cell code)
{
if (code == 0 || n->error_reg < 0 || n->fault_vector < 0 || n->stopped) return 0;
+2 -62
View File
@@ -51,10 +51,6 @@ static unsigned loaded(unsigned k)
/* the programme ends by waiting at a port nothing is wired to */
static void wait_for_ever(void) { LIT(PB + 7); O(BANG_B); O(FETCH_B); (void)v4_asm_label(&as); } /* and the last word is written out */
/* a device that says whether it has something pending */
static int *dev_has;
static int device_has(void *self) { (void)self; return *dev_has; }
/* Let time pass until nothing more can happen, or `max` steps. */
static unsigned settle(unsigned max)
{
@@ -435,62 +431,6 @@ int main(void)
CHECK(ND(a)->n.asking && ND(a)->n.request == 5 && ND(c)->n.reading && ND(c)->n.mem[OUT] == 0, "looking takes nothing and gives nothing: both wait as they did");
CHECK(!ND(b)->n.stopped && ND(b)->n.reading, "and the one that looked did not wait to look");
/* ---- a node blocked on the first word of a message, while a device of its own has something for it ---- */
{
static int has; /* what the device says it has pending */
static stream none;
static v4_device dev;
v4_fabric_init(&f, places, 4);
for (i = 0; i < 3; i++) v4_node_reset(&pool[i].n);
a = loaded(0); /* looks about, then writes two words to its port 0 */
LIT(PB + (v4_cell)V4_PORTS + 3); O(BANG_B); O(FETCH_B); O(DROP);
LIT(PB + 0); O(BANG_B); LIT(1); O(STORE_B); LIT(2); O(STORE_B); wait_for_ever();
b = loaded(1); /* never reads */
LIT(OUT); O(BANG_A);
{
v4_cell again = v4_asm_label(&as);
O(FETCH_A); LIT(1); O(ADD); O(STORE_A);
v4_asm_branch(&as, V4_OP_JUMP, again);
}
CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 3), "a writer that looks first, wired to a node that never reads");
dev.take = stream_take; dev.give = 0; dev.self = &none; dev.pending = device_has; has = 1; dev_has = &has;
CHECK(v4_fabric_wire_device(&f, a, 5, &dev), "and to a device, which has something for it");
for (i = 0; i < 40; i++) (void)v4_fabric_step(&f);
CHECK(ND(a)->n.asking && ND(a)->n.request == 1 && v4_node_words_since_look(&ND(a)->n) == 0, "the writer is blocked on its first word, and waits: the fabric has no error for it");
v4_fabric_interrupt_error(&f, 21);
for (i = 0; i < 40; i++) (void)v4_fabric_step(&f);
CHECK(ND(a)->n.asking && ND(a)->n.faults == 0, "nor is a bare node let go when it has: it cannot take an error");
v4_node_error_attach(&ND(a)->n, OUT + 20);
v4_node_fault_attach(&ND(a)->n, 900);
has = 0;
for (i = 0; i < 40; i++) (void)v4_fabric_step(&f);
CHECK(ND(a)->n.asking && ND(a)->n.faults == 0, "a node that can take one waits all the same while the device has nothing for it");
has = 1;
(void)v4_fabric_step(&f);
CHECK(!ND(a)->n.asking && ND(a)->n.fault_kind == V4_FAULT_RAISED && ND(a)->n.fault_addr == 21 && ND(a)->n.mem[OUT + 20] == 21,
"when it has, the writer is let go and the error raised on it");
/* once the first word has gone, it is not let go: the message must be finished */
v4_fabric_init(&f, places, 4);
for (i = 0; i < 3; i++) v4_node_reset(&pool[i].n);
a = loaded(0);
LIT(PB + (v4_cell)V4_PORTS + 3); O(BANG_B); O(FETCH_B); O(DROP);
LIT(PB + 0); O(BANG_B); LIT(1); O(STORE_B); LIT(2); O(STORE_B); wait_for_ever();
b = loaded(1); /* reads one word, and no more */
LIT(PB + 3); O(BANG_B); O(FETCH_B); LIT(OUT); O(BANG_A);
{
v4_cell again = v4_asm_label(&as);
O(FETCH_A); LIT(1); O(ADD); O(STORE_A);
v4_asm_branch(&as, V4_OP_JUMP, again);
}
CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 3) && v4_fabric_wire_device(&f, a, 5, &dev), "the same, to a node that reads one word and no more");
v4_node_error_attach(&ND(a)->n, OUT + 20);
v4_node_fault_attach(&ND(a)->n, 900);
v4_fabric_interrupt_error(&f, 21);
for (i = 0; i < 60; i++) (void)v4_fabric_step(&f);
CHECK(ND(a)->n.asking && ND(a)->n.request == 2 && ND(a)->n.faults == 0, "blocked on its second word with the device still pending, the writer waits");
}
/* ---- messages on the wire (MESH.md 7d): the engine only ---- */
{
static v4_wire_queue qpool[8];
@@ -800,7 +740,7 @@ int main(void)
CHECK(!ND(c)->n.doing && !ND(a)->n.doing && ND(a)->n.how == 1, "room that comes in the step the node goes to sleep wakes it: no wake-up is lost");
/* a device's take is a take */
{
static const v4_device dev = { 0, 0, 0, 0 };
static const v4_device dev = { 0, 0, 0 };
v4_cell hh[7], tt[V4_WIRE_CELLS / 4];
CHECK(v4_fabric_wire_device(&f, a, 4, &dev), "a device on a third wire");
fill(f.place[a].wire[4].tx, 0);
@@ -855,7 +795,7 @@ int main(void)
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;
ks.took_n = 0; kern.take = stream_take; kern.give = 0; kern.self = &ks;
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,
+1 -1
View File
@@ -45,7 +45,7 @@ static v4_wire_queue queues[QUEUES];
/* ---- the console: a device on a port ---- */
#define CONSOLE_ID 1
static const v4_device console = { 0, 0, 0, 0 }; /* it takes and gives no words: only whole messages */
static const v4_device console = { 0, 0, 0 }; /* it takes and gives no words: only whole messages */
static unsigned hera, mid, far; /* where the three nodes are: 10, 11, 12 */
static char printed[32768]; /* what has come back since the console last sent */
static unsigned printed_len;
+82 -2
View File
@@ -38,11 +38,11 @@ static v4_wire_queue queues[QUEUES];
/* ---- the console: a device on a port ---- */
#define CONSOLE_ID 1
static const v4_device console = { 0, 0, 0, 0 }; /* it takes and gives no words: only whole messages */
static const v4_device console = { 0, 0, 0 }; /* it takes and gives no words: only whole messages */
/* a kernel on a node's port 0: it takes the words written to it, and no messages (MESH.md 7d.5) */
static unsigned kernel_words;
static int kernel_take(void *self, v4_cell value) { (void)self; (void)value; kernel_words++; return 1; }
static const v4_device kernel_dev = { kernel_take, 0, 0, 0 };
static const v4_device kernel_dev = { kernel_take, 0, 0 };
static unsigned hera, mid, far; /* where the three nodes are: 10, 11, 12 */
static char printed[32768]; /* what has come back since the console last sent */
static unsigned printed_len;
@@ -246,6 +246,56 @@ static void watch_far_waits(void)
if (waits_for_room(far)) { saw_room_wait++; if (going_from(far, 3) && going_from(far, 3)->used == V4_WIRE_CELLS - 8u) saw_full++; }
}
/* ---- a node removed at every step of an exchange (MESH.md 7d.7, acceptance 6) ---- */
/* 1 if the node is doing nothing and waits for nothing but a message: asleep, and blocked at no port. */
static int at_rest(unsigned id)
{
const v4_fabric_node *x = v4_fabric_node_at(&f, id);
return x && asleep(id) && !x->n.asking && !x->n.reading && !x->n.stopped;
}
/* 1 if what came back ends with the answer to `1 2 + .`, asked by the word Q that each node was given; a wait
* the removal left is first ended by the line, and says so. */
#define ASK ": Q 1 2 + . ;"
static int answers(v4_cell node, unsigned id)
{
const char *got = tell(node, "Q");
size_t len = strlen(got);
return len >= 2 && strcmp(got + len - 2, "3 ") == 0 && ended >= 1 && ended_from == node && at_rest(id);
}
/* The exchange that `text`, sent to `node`, begins is played from the mesh as kept, once for every step it
* takes, with the node at place `gone` removed at that step. Every node left must come to rest, blocked in
* nothing, and answer. With the middle node gone the far one is wired to the first, as whoever removed it
* would, so that it can be asked. How many steps the exchange takes; how many removals went wrong, and
* the first of them. */
static v4_fabric_node now_pool[3];
static v4_place now_places[3];
static v4_wire_queue now_queues[QUEUES];
static v4_fabric now_f;
static unsigned removed_at_every_step(v4_cell node, const char *text, unsigned gone, unsigned *wrong, unsigned *first_wrong)
{
unsigned long before;
unsigned whole, s;
*wrong = 0; *first_wrong = 0;
put_back();
before = steps_run;
if (!put_text(node, text) || !run()) { *wrong = 1; return 0; }
whole = (unsigned)(steps_run - before);
put_back();
if (!put_text(node, text)) { *wrong = 1; return 0; }
for (s = 0; s <= whole; s++) {
int ok;
memcpy(now_pool, pool, sizeof pool); memcpy(now_places, places, sizeof places); memcpy(now_queues, queues, sizeof queues); now_f = f; /* the exchange, s steps on */
ok = v4_fabric_remove(&f, gone) == &pool[gone] && run();
ok = ok && at_rest(hera) && (gone == mid ? at_rest(far) : at_rest(mid));
if (ok && gone == mid) ok = v4_fabric_wire(&f, hera, 2, far, 2) && answers(12, far) && answers(10, hera);
else if (ok) ok = answers(11, mid) && answers(10, hera);
if (!ok) { if (!*wrong) *first_wrong = s; (*wrong)++; }
memcpy(pool, now_pool, sizeof pool); memcpy(places, now_places, sizeof places); memcpy(queues, now_queues, sizeof queues); f = now_f;
(void)v4_fabric_step(&f); (void)console_takes();
}
return whole;
}
int main(void)
{
unsigned i;
@@ -944,6 +994,36 @@ int main(void)
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");
/* ---- A NODE REMOVED AT EVERY STEP (MESH.md 7d.7, acceptance 6) ----
* Three exchanges, each played once whole and then once for every step it takes, with node 11 removed
* at that step, and again with node 12: the nodes left come to rest, blocked in nothing, and answer.
* What is typed is a word defined beforehand, and so is what a node left is asked (Q, which is
* `1 2 + .`): a line of several words is mostly the dictionary searched, thousands of steps in which the
* mesh does nothing, and every one of them would be a removal played to the end. */
{
static const struct { const char *what, *set10, *set11, *set12; v4_cell node; const char *text; } ex[3] = {
{ "text from the console for node 12, what it prints and how it ended", "1 DROP", "1 DROP", ": A 7 8 * . ;", 12, "A" },
{ "node 11 SENDs node 12 text and waits for its answer", "1 DROP", ": T S\" Q\" 12 SEND 12 AWAIT . ;", "1 DROP", 11, "T" },
{ "a message node 12 has no way for, and its NACK to node 10", "55 2 ROUTE : N S\" 1 DROP\" 55 SEND ;", "55 3 ROUTE", "NO-ROUTES 1 2 ROUTE 10 2 ROUTE 11 2 ROUTE", 10, "N" }
};
unsigned e, g, whole, wrong, first;
step_cap = 2000000;
for (e = 0; e < 3; e++) {
CHECK(row() && told(10, ex[e].set10) && told(11, ex[e].set11) && told(12, ex[e].set12) && told(10, ASK) && told(11, ASK) && told(12, ASK), "a row made afresh for: %s", ex[e].what);
step_cap = 2000000;
keep();
for (g = 1; g <= 2; g++) {
whole = removed_at_every_step(ex[e].node, ex[e].text, g == 1 ? mid : far, &wrong, &first);
CHECK(whole > 0 && wrong == 0, "%s, in %u steps: with node %u removed at each of them the rest come to rest and answer: %u did not, the first at step %u",
ex[e].what, whole, 10u + g, wrong, first);
}
}
put_back();
CHECK(is_empty(tell(10, "N")) && pool[hera].n.mem[REFUSED] == 1 && pool[far].n.mem[LOST] == 1, "the last of them, whole: node 12 let the message go and node 10 was told it was refused");
step_cap = 20000000;
}
printf(" %d checks, %d failures\n", checks, failures);
return failures != 0;
}
+3 -3
View File
@@ -142,7 +142,7 @@ static int host_born(void *self)
v4_node_fault_attach(&pool[k].n, w_fault);
v4_blocks_init(&node_blocks[k], BUF0_W);
if (k != 0) { /* Hera's kernel is wired where she is made */
node_kernel[k].take = node_kernel_take; node_kernel[k].give = 0; node_kernel[k].self = &pool[k]; node_kernel[k].pending = 0;
node_kernel[k].take = node_kernel_take; node_kernel[k].give = 0; node_kernel[k].self = &pool[k];
if (!v4_fabric_wire_kernel(&f, (unsigned)place, 0, &node_kernel[k])) return -1; /* it takes words, and no messages */
}
return place;
@@ -196,7 +196,7 @@ static int kernel_take(void *self, v4_cell value) /* a request */
if (value < FIRST_REQUEST || !v4_manage_serve(&manage, hera_place, (unsigned)(value - FIRST_REQUEST))) refused++;
return 1;
}
static const v4_device kernel = { kernel_take, kernel_give, 0, 0 };
static const v4_device kernel = { kernel_take, kernel_give, 0 };
/* ---- the console: a device on Hera's port 1 ----
* It speaks whole messages: it puts them on the wire to Hera and takes them
@@ -209,7 +209,7 @@ static int ended;
static v4_cell ended_from, ended_how;
static unsigned post_passed[32]; /* by node number: POST tallies with no failures seen from it */
static unsigned post_other; /* tallies with failures */
static const v4_device console = { 0, 0, 0, 0 };
static const v4_device console = { 0, 0, 0 };
static unsigned console_takes(void)
{