fix(v4.0.0): a node blocked at a port with no one on it is given an error, not left there
A node writing to a node that was stuck, and was then killed, stayed blocked for ever: killing a stuck node could cost its neighbours. And on the hosted and bare-metal products a write to an empty port, 5 7 PORT!, ended the program with "the node stopped". Now a node that can take an error, blocked writing to or reading from one port that nothing is wired to -- nothing ever was, or what was there has been killed or the wire cut -- has error 18, No one on that port, raised on it and goes on. A bare node waits as on the fabric; so does a node whose neighbour is asleep, and one reading "any port". test_host_unit.c: Hera kills node 14 while node 12 is blocked writing to it. It failed first: 12 stayed blocked. test_fabric.c: a bare node still waits. hosted-check types 5 7 PORT! and goes on; it failed first too. make -C v4 test, sanitize and hosted-check pass; amd64, aarch64 and riscv64 boot, POST 538 of 538, dict_hash 0x5f0a949a6fc8ef2b on all six: logs/20261007-121743, -122008, -122337. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
18adf59091
commit
bc6deab3f5
@@ -17,9 +17,15 @@ void v4_fabric_init(v4_fabric *f, v4_place *places, unsigned capacity)
|
||||
unsigned i;
|
||||
f->place = places;
|
||||
f->capacity = capacity;
|
||||
f->gone_error = 0;
|
||||
for (i = 0; i < capacity; i++) clear_place(&places[i]);
|
||||
}
|
||||
|
||||
void v4_fabric_gone_error(v4_fabric *f, v4_cell code)
|
||||
{
|
||||
f->gone_error = code;
|
||||
}
|
||||
|
||||
void v4_fabric_grow(v4_fabric *f, v4_place *places, unsigned capacity)
|
||||
{
|
||||
unsigned i;
|
||||
@@ -196,5 +202,16 @@ 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 at one port that nothing is wired to */
|
||||
if (f->gone_error != 0)
|
||||
for (i = 0; i < f->capacity; i++) {
|
||||
v4_node *n;
|
||||
if (!awake(f, i)) continue;
|
||||
n = &f->place[i].node->n;
|
||||
if ((n->asking && f->place[i].wire[n->ask_port].kind == V4_WIRE_NONE)
|
||||
|| (n->reading && !n->given && n->read_port != V4_PORT_ANY && f->place[i].wire[n->read_port].kind == V4_WIRE_NONE))
|
||||
done += (unsigned)v4_node_port_gone(n, f->gone_error);
|
||||
}
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
@@ -222,3 +222,13 @@ void v4_node_port_served(v4_node *n)
|
||||
{
|
||||
n->asking = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
if (n->asking) n->asking = 0;
|
||||
else if (n->reading && !n->given && n->read_port != V4_PORT_ANY) n->reading = 0;
|
||||
else return 0;
|
||||
v4_node_store(n, n->error_reg, code); /* raises it: P is the node's handler now */
|
||||
return 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user