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:
co-authored by
Claude Opus 5.5
parent
353783726d
commit
ec817a8264
+12
-8
@@ -251,17 +251,20 @@ header CMOVE
|
||||
\ ( port to -- ) take in a message and keep it
|
||||
: (TAKE) (TAKE-HDR) jump (TAKE-KEEP)
|
||||
|
||||
\ ( -- flag ) THE WAIT, once. Whatever has been offered stands until
|
||||
\ this returns. Zero: a word came for this node instead; that whole
|
||||
\ message has been taken in and kept, (TAKE), and its seven words are
|
||||
\ still in (MQ-HDR). Not zero: an offer was taken; B is at the port it
|
||||
\ was taken on, and (GATE-PORT) holds that port's address.
|
||||
\ ( -- how ) THE WAIT, once. Whatever has been offered stands until
|
||||
\ this returns. 0: a word came for this node instead; that whole message
|
||||
\ has been taken in and kept, (TAKE), and its seven words are still in
|
||||
\ (MQ-HDR). -1: an offer was taken; B is at the port it was taken on, and
|
||||
\ (GATE-PORT) holds that port's address. 1: there is nothing on a port
|
||||
\ that had an offer: no one will ever take it.
|
||||
: (OFFERS)
|
||||
(WAIT) b! @b push (PORT)+9 b! @b \ ( which ) R: the word
|
||||
dup -PORTS + -if TAKEN
|
||||
drop (PORT) + dup b! pop (TAKE) 0 ; \ a word, from that port: the message's first
|
||||
TAKEN: (PORT) + (GATE-PORT) a! ! drop pop drop
|
||||
TAKEN: dup -PORTS + -if NOONE \ ( which k x ) k: the port, by its number
|
||||
drop (PORT) + (GATE-PORT) a! ! drop pop drop
|
||||
(GATE-PORT) a! @ b! -1 ;
|
||||
NOONE: drop drop drop pop drop 1 ;
|
||||
|
||||
\ ( w port -- ) BEGIN A MESSAGE: the word, its first, is offered on the
|
||||
\ port, by its address, until it is taken; whatever is written to this
|
||||
@@ -274,11 +277,12 @@ header CMOVE
|
||||
\ the messages waiting and is done next. It is how a node whose text must
|
||||
\ begin a message to a node that is stuck is typed to. Not while (QUIET)
|
||||
\ is set: what waits then is no text's doing.
|
||||
\ With nothing on the port the fabric raises error 18.
|
||||
\ With nothing on the port it is error 18.
|
||||
: (GATE1) ( port -- )
|
||||
(GATE-PORT) a! !
|
||||
L: (GATE-WORD) a! @ (GATE-PORT) a! @ -PORTS - 4 + a! ! \ the offer
|
||||
(OFFERS) if CAME drop ;
|
||||
(OFFERS) if CAME -if NOONE drop ;
|
||||
NOONE: drop NODE-ERROR b! 18 !b ; \ no one on that port
|
||||
CAME: drop
|
||||
(QUIET) a! @ if TEXTS drop jump L
|
||||
TEXTS: drop
|
||||
|
||||
+50
-52
@@ -118,30 +118,35 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro
|
||||
\ text into TIB.
|
||||
\ TEXT IS NOT BEGUN WHILE THE ANSWER TO ITS SENDER'S LAST IS STILL HERE:
|
||||
\ a message this node made itself, (FINISH), is ahead of it, to that
|
||||
\ sender. (A-WORD) is whom such a message seen so far is to: -1 none,
|
||||
\ -2 more than one node, and then no text is begun. A NACK or a GONE for
|
||||
\ this node is never held back.
|
||||
\ sender. Whom each such message seen so far is to is noted in (PAY-K),
|
||||
\ which nothing else is using now, and (A-WORD) is how many: at most as
|
||||
\ many as there are ports, and with more than that no text is begun. A
|
||||
\ NACK or a GONE for this node is never held back.
|
||||
: (MINE?)
|
||||
0 (A-FOUND) a! ! -1 (A-WORD) a! !
|
||||
0 (A-FOUND) a! ! 0 (A-WORD) a! !
|
||||
(MQ#) a! @ (A-LEFT) a! !
|
||||
L: (A-LEFT) a! @ if END drop
|
||||
(MQ-NEXT)
|
||||
(A-FOUND) a! @ if LOOK drop jump KEEP
|
||||
LOOK: drop
|
||||
(MQ-HDR)+7 a! @ -if THEIRS
|
||||
drop (A-WORD) a! @ 1 + if FIRST \ this node's own:
|
||||
drop (A-WORD) a! @ (MQ-HDR) a! @ xor if SAME
|
||||
drop -2 (A-WORD) a! ! jump KEEP
|
||||
FIRST: drop (MQ-HDR) a! @ (A-WORD) a! ! jump KEEP
|
||||
SAME: drop jump KEEP
|
||||
drop (A-WORD) a! @ -PORTS + -if MANY \ this node's own: whom it is to is noted
|
||||
drop (MQ-HDR) a! @ push (A-WORD) a! @ dup 1 + ! (PAY-K) + a! pop !
|
||||
jump KEEP
|
||||
MANY: drop PORTS-1 2 + (A-WORD) a! ! jump KEEP \ more than can be noted
|
||||
THEIRS: drop
|
||||
(MQ-HDR) a! @ (ME) a! @ xor if MINE drop jump KEEP
|
||||
MINE: drop
|
||||
(MQ-HDR)+2 a! @ -1 + if TEXT drop jump TAKE
|
||||
TEXT: drop
|
||||
(A-WORD) a! @ 2 + if HOLD
|
||||
drop (A-WORD) a! @ (MQ-HDR)+1 a! @ xor if HOLD
|
||||
drop
|
||||
(A-WORD) a! @ if TAKE0 \ no answer is waiting to go
|
||||
dup -PORTS + -1 + -if HOLD2 drop \ ( n count )
|
||||
(MQ-HDR)+1 a! @ SWAP -1 + (PAY-K) a! \ ( n from count-1 )
|
||||
FOR dup @+ xor if HIT drop NEXT
|
||||
drop jump TAKE \ none of them is to this text's sender
|
||||
HIT: drop drop pop drop jump KEEP
|
||||
HOLD2: drop drop jump KEEP
|
||||
TAKE0: drop
|
||||
TAKE: 1 (A-FOUND) a! !
|
||||
(MQ-HDR) a! @ (MSG) a! ! (MQ-HDR)+1 a! @ (MSG)+1 a! ! (MQ-HDR)+2 a! @ (MSG)+2 a! !
|
||||
(MQ-HDR)+3 a! @ (MSG)+3 a! ! (MQ-HDR)+4 a! @ (MSG)+4 a! ! (MQ-HDR)+5 a! @ (MSG)+5 a! !
|
||||
@@ -150,7 +155,6 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro
|
||||
-1 + FOR (MQ@) over a! ! 1 + NEXT
|
||||
drop jump L
|
||||
EMPTY: drop drop jump L
|
||||
HOLD: drop
|
||||
KEEP: (A-BACK) (A-TEXT) jump L
|
||||
END: drop (A-FOUND) a! @ ;
|
||||
|
||||
@@ -239,7 +243,7 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro
|
||||
(PAY-SET) (FWD-SET) if SET drop jump L \ one was let go: what is owed has changed
|
||||
SET: drop
|
||||
(MQ#) a! @ (OWED#) a! @ + if BLOCK drop
|
||||
(OFFERS) if CAME drop
|
||||
(OFFERS) if CAME -if CAME drop \ nothing on a port: what was for it is let go next time round
|
||||
(GATE-PORT) a! @ (PORT) - (PAY-K) + a! @ \ what was offered on the port it was taken on
|
||||
-if OWED drop (FWD-GO) jump L
|
||||
OWED: -1 + (PAY-GO) jump L
|
||||
@@ -328,10 +332,18 @@ header NO-ROUTE
|
||||
|
||||
\ ( about node type -- ) send the node a message of one word, `about`:
|
||||
\ a NACK is type 4, a GONE type 5 (MESH.md 7b). With no way to the node
|
||||
\ it is error 12.
|
||||
\ it is error 12. It is put with the messages waiting and goes from
|
||||
\ (IDLE), or from AWAIT, as how text ended does ((FINISH)): so telling a
|
||||
\ node that is stuck does not hold up the telling of the next. With no
|
||||
\ room at all it is offered here.
|
||||
: (SEND1)
|
||||
push dup (PORT-FOR) if NOWAY
|
||||
(GATE) pop (HDR) 4 !b !b ;
|
||||
push dup (PORT-FOR) if NOWAY \ ( about node port ) R: type
|
||||
1 (MQ#) a! @ + -MQ-ROOM + -if FULL drop
|
||||
SWAP (MQ!) (ME) a! @ (MQ!) pop (MQ!) \ to, from, type
|
||||
0 (MQ!) 0 (MQ!) 0 (MQ!) 4 (MQ!) \ four characters long
|
||||
0 SWAP - (MQ!) \ by that port, kept below zero: this node's own
|
||||
(MQ!) ; \ about
|
||||
FULL: drop (GATE) pop (HDR) 4 !b !b ;
|
||||
NOWAY: drop drop drop pop drop NODE-ERROR b! 12 !b ;
|
||||
|
||||
\ ( n node -- ) tell the node that node n is gone. It acts on that only
|
||||
@@ -439,52 +451,38 @@ header SEND-ON
|
||||
LEFT: drop NODE-ERROR b! 20 !b ;
|
||||
|
||||
\ ( node -- how ) WAIT FOR THE NODE'S WORD OF HOW TEXT ENDED: 0 QUIT,
|
||||
\ 1 completed, 2 an error. This node is blocked reading its ports until a
|
||||
\ message of type 3 comes for it from that node; every other message that
|
||||
\ comes meanwhile is kept with the messages waiting. (AWAIT-FROM) holds the
|
||||
\ node while it waits, and 0 otherwise.
|
||||
\ 1 completed, 2 an error: a message of type 3 for this node from that
|
||||
\ node. (AWAIT-FROM) holds the node while it waits, and 0 otherwise.
|
||||
\ THE WAIT ALSO ENDS, in an error, when the answer is not going to come
|
||||
\ (MESH.md section 7b): a NACK about that node, error 19, Message refused;
|
||||
\ or a GONE about it from this node's centre, error 20, Node gone. A NACK
|
||||
\ about another node is counted, and a GONE about another has its way
|
||||
\ forgotten, as they would be if this node were not waiting. A GONE is
|
||||
\ believed only if this node's centre sent it: (CENTRE).
|
||||
\ WHAT HAS COME ALREADY is looked through first, (A-QUEUE): the answer, a
|
||||
\ NACK or a GONE may have been taken in before the wait began, while this
|
||||
\ node was waiting to write, and is then with the messages waiting.
|
||||
\ AND A LINE FROM THE CONSOLE BREAKS IT (7b.6): text for this node from its
|
||||
\ console is kept, as any message is, the wait ends in error 21,
|
||||
\ Interrupted, and the text is then done as usual. It is the one way to
|
||||
\ end a wait on a node that is alive and never answers, short of Hera's
|
||||
\ killing that node.
|
||||
\ console ends the wait in error 21, Interrupted, and is then done as
|
||||
\ usual. It is the one way to end a wait on a node that is alive and
|
||||
\ never answers, short of Hera's killing that node.
|
||||
\ WHILE IT WAITS THE NODE DOES WHAT (IDLE) DOES, but for beginning text:
|
||||
\ the messages waiting are looked through for what would end the wait,
|
||||
\ (A-QUEUE); what it has for other nodes and the refusals it owes are
|
||||
\ offered, and it sleeps in the wait (MESH.md 7c); what comes is taken in
|
||||
\ and kept, and it looks again. So what passes through a node is not
|
||||
\ kept back by its waiting, and what it sent before it began to wait --
|
||||
\ a GONE, say -- goes.
|
||||
header AWAIT
|
||||
: AWAIT
|
||||
(AWAIT-FROM) a! !
|
||||
(A-QUEUE)
|
||||
(A-FOUND) a! @ if WAIT jump (A-END)
|
||||
L: (A-QUEUE)
|
||||
(A-FOUND) a! @ if WAIT jump (A-END)
|
||||
WAIT: drop
|
||||
L: (PORT)+8 b! @b (PORT)+9 b! @b (PORT) + dup b! SWAP (TAKE-HDR)
|
||||
(MQ-HDR) a! @ (ME) a! @ xor if A1 drop jump KEEP
|
||||
A1: drop (MQ-HDR)+2 a! @ \ for this node: its type
|
||||
-1 + if TEXT -2 + if ANSWER -1 + if NACK -1 + if GONE drop jump KEEP
|
||||
TEXT: drop (A-CONSOLE) (MQ-HDR)+1 a! @ xor if BREAK drop jump KEEP \ text: from the console?
|
||||
BREAK: drop (TAKE-KEEP) 4 jump (A-END) \ kept, to be done next; and the wait is over
|
||||
ANSWER: drop (MQ-HDR)+1 a! @ (AWAIT-FROM) a! @ xor if A3 drop jump KEEP
|
||||
A3: drop (MQ-HDR)+6 a! @ -4 + if A4 drop jump KEEP
|
||||
A4: drop 0 (AWAIT-FROM) a! ! @b ; \ its one word
|
||||
NACK: drop (MQ-HDR)+6 a! @ -4 + if N4 drop jump KEEP
|
||||
N4: drop @b (AWAIT-FROM) a! @ xor if REFUSED \ about the node waited for?
|
||||
drop (REFUSED) a! @ 1 + ! jump L \ another: counted
|
||||
REFUSED: drop 2 jump (A-END)
|
||||
GONE: drop (MQ-HDR)+6 a! @ -4 + if G4 drop jump KEEP
|
||||
G4: drop @b \ the node that is gone
|
||||
(CENTRE) if NOC (MQ-HDR)+1 a! @ xor if CENTRE \ only its centre is believed
|
||||
drop drop jump L
|
||||
NOC: drop drop jump L
|
||||
CENTRE: drop dup NO-ROUTE
|
||||
(AWAIT-FROM) a! @ xor if LEFT drop jump L
|
||||
LEFT: drop 3 jump (A-END)
|
||||
KEEP: (TAKE-KEEP) jump L
|
||||
(PAY-SET) (FWD-SET) if SET drop jump L \ one was let go: this node may have been told so
|
||||
SET: drop
|
||||
(OFFERS) if CAME -if CAME drop
|
||||
(GATE-PORT) a! @ (PORT) - (PAY-K) + a! @
|
||||
-if OWED drop (FWD-GO) jump L
|
||||
OWED: -1 + (PAY-GO) jump L
|
||||
CAME: drop jump L
|
||||
|
||||
\ ( w port -- ) write a cell to the port, by its number. It waits until
|
||||
\ the neighbour has taken it. This is how a node is sent a capsule of F18
|
||||
|
||||
Reference in New Issue
Block a user