feat(v4.0.0): the wait in the engine -- a node offers a word and sleeps

A node stores a word to offer on any of its ports and fetches the wait: it
is blocked until a word comes for it or one of its offers is taken, and
the fabric does the handing over in one step.  The port block moves in
the nucleus's map to make room for the new addresses.  Nothing uses it
yet.  MESH.md 7c; plan step 6d task 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-07 23:15:11 -04:00
co-authored by Claude Opus 5.5
parent dfabfa46f6
commit 075385ab63
6 changed files with 275 additions and 8 deletions
+54 -6
View File
@@ -93,7 +93,13 @@ void v4_node_store(v4_node *n, v4_cell addr, v4_cell value)
n->asking = 1;
return;
}
if (port >= 0) { v4_node_fault(n, V4_FAULT_ADDRESS, addr); return; } /* "any" and "which port" are not written to */
if (port >= (int)V4_PORT_OFFER && port < (int)V4_PORT_WAIT) { /* an offer: remembered until the wait */
unsigned k = (unsigned)port - V4_PORT_OFFER;
n->offer[k] = value;
n->offers |= 1u << k;
return;
}
if (port >= 0) { v4_node_fault(n, V4_FAULT_ADDRESS, addr); return; } /* "any", "which port" and the rest are not written to */
}
/* The stack registers: a store empties the stack. -1 when not attached. */
if (addr == n->dstack_reg) { v4_dstack_clear(&n->ds); return; }
@@ -122,6 +128,14 @@ v4_cell v4_node_fetch(v4_node *n, v4_cell 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_PORT_WAIT) {
/* the wait: the word that came, or 0 for an offer taken */
if (!n->given) return 0;
n->given = 0;
n->last_from = n->given_port;
return n->given_value;
}
if (port >= (int)V4_PORT_OFFER) return 0; /* an offer is not read back */
if (port >= 0) {
/* the word its neighbour wrote; v4_node_read_ready has said it is there */
if (!n->given) return 0;
@@ -180,6 +194,9 @@ void v4_node_port_attach(v4_node *n, v4_cell base)
n->writers = 0;
n->readers = 0;
n->since_look = 0;
n->offers = 0;
n->waiting = 0;
n->offer_asked = 0;
}
void v4_node_port_status(v4_node *n, unsigned writers, unsigned readers)
@@ -190,17 +207,18 @@ void v4_node_port_status(v4_node *n, unsigned writers, unsigned readers)
int v4_node_port_index(const v4_node *n, v4_cell addr)
{
if (n->port < 0 || addr < n->port || addr > n->port + (v4_cell)V4_PORTS + 3) return -1;
if (n->port < 0 || addr < n->port || addr > n->port + (v4_cell)V4_PORT_WAIT) return -1;
return (int)(addr - n->port);
}
int v4_node_read_ready(v4_node *n, v4_cell addr)
{
int port = v4_node_port_index(n, addr);
if (port < 0 || port > (int)V4_PORT_ANY) return 1;
if (n->given && (port == (int)V4_PORT_ANY || (unsigned)port == n->given_port)) return 1;
if (port < 0 || (port > (int)V4_PORT_ANY && port != (int)V4_PORT_WAIT)) return 1;
if (n->given && (port >= (int)V4_PORT_ANY || (unsigned)port == n->given_port)) return 1;
n->reading = 1;
n->read_port = (unsigned)port;
n->waiting = port == (int)V4_PORT_WAIT; /* the wait is a read of any port, with offers standing */
n->read_port = n->waiting ? V4_PORT_ANY : (unsigned)port;
return 0;
}
@@ -210,6 +228,31 @@ void v4_node_port_give(v4_node *n, unsigned port, v4_cell value)
n->given_value = value;
n->given_port = port;
n->reading = 0;
if (n->waiting) { n->waiting = 0; n->offers = 0; } /* the wait is over: every offer is withdrawn */
}
int v4_node_in_wait(const v4_node *n)
{
return n->waiting && n->reading && !n->given;
}
int v4_node_offer_taken(v4_node *n, unsigned k)
{
if (!v4_node_in_wait(n) || k >= V4_PORTS || !(n->offers & (1u << k))) return 0;
v4_node_port_give(n, V4_PORTS + k, 0);
return 1;
}
int v4_node_offer_as_write(v4_node *n)
{
unsigned k;
if (!v4_node_in_wait(n) || n->offers == 0 || n->asking) return 0;
for (k = 0; !(n->offers & (1u << k)); k++) { }
n->request = n->offer[k];
n->ask_port = k;
n->asking = 1;
n->offer_asked = 1;
return 1;
}
void v4_node_born(v4_node *n, v4_cell base)
@@ -223,6 +266,10 @@ void v4_node_port_served(v4_node *n)
{
n->asking = 0;
n->since_look++;
if (n->offer_asked) { /* what was served was an offer: the wait is over */
n->offer_asked = 0;
v4_node_port_give(n, V4_PORTS + n->ask_port, 0);
}
}
unsigned v4_node_words_since_look(const v4_node *n)
@@ -233,7 +280,8 @@ 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->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; }
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 */