fix(v4.0.0): a waiting node goes on passing on and paying; KILL is not held by a stuck node

Found in the five-node test, each with a check that failed first:
- A node with answers it could not give to two stuck senders began no
  text at all.  It now holds back only text from a sender whose own
  answer is still with it.
- KILL waited to tell a stuck node, and a typed line that broke it left
  the nodes after it untold.  GONE is put with the messages waiting, as
  how text ended is, and goes when it can.
- So that 'tell, then wait' still works, AWAIT does what (IDLE) does but
  for beginning text: it looks through the messages waiting, offers what
  is to be passed on and what is owed, and sleeps in the wait.  A waiting
  node no longer keeps back what passes through it.
- A node in the wait with an offer on a port that turns out to have
  nothing on it is woken and told so (which port: 2 * V4_PORTS + k); no
  error is raised on it.  (GATE) makes it error 18; (IDLE) and AWAIT let
  the message go.  Before, removing a node raised 'No one on that port'
  on the unrelated text of a neighbour that had something queued for it.

make -C v4 test and sanitize at both widths, hosted-check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-08 01:00:33 -04:00
co-authored by Claude Opus 5.5
parent 353783726d
commit ec817a8264
9 changed files with 130 additions and 99 deletions
+14 -2
View File
@@ -243,6 +243,14 @@ int v4_node_offer_taken(v4_node *n, unsigned k)
return 1;
}
int v4_node_offer_gone(v4_node *n, unsigned k)
{
if (n->error_reg < 0 || n->fault_vector < 0 || n->stopped) return 0;
if (!v4_node_in_wait(n) || k >= V4_PORTS || !(n->offers & (1u << k))) return 0;
v4_node_port_give(n, 2u * V4_PORTS + k, 0);
return 1;
}
int v4_node_offer_as_write(v4_node *n)
{
unsigned k;
@@ -280,8 +288,12 @@ unsigned v4_node_words_since_look(const v4_node *n)
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; if (n->offer_asked) { n->offer_asked = 0; n->reading = 0; n->waiting = 0; n->offers = 0; } }
else if (v4_node_in_wait(n) && n->offers != 0) { n->reading = 0; n->waiting = 0; n->offers = 0; }
if (n->asking && n->offer_asked) { /* what it wrote was an offer: it is told, not faulted */
n->asking = 0; n->offer_asked = 0;
v4_node_port_give(n, 2u * V4_PORTS + n->ask_port, 0);
return 1;
}
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 */