fix(v4.0.0): step 6d after its review -- no error in the middle of the messages waiting, no offer left standing
Ruled 2026-10-08: A, B, C, D and the guard for a half message. Each with a scene in test_host_mesh.c that failed first. A. The words of a message after its first are written from the passes over the messages waiting by (!W): an offer and a wait for that offer only (a new engine address). A reader removed in mid-message makes no error; the rest is let go and counted. Before, the error left the messages waiting in pieces and the node going round for ever. B. A store to the wait withdraws every offer; (GATE1) and (PAY-SET) do it first. Before, text begun after a node went round without sleeping could go to the port of an older offer: text for one node was done by another. C. What a finished text printed is put with the messages waiting, as how it ended is. With no room either is let go and counted; neither is begun as a message from (FINISH) any more, where a stuck node on the way held the whole node. D. Only what a sender is owed from an earlier text -- its output, how it ended -- holds that sender's next text back; a GONE does not; and what cannot be noted holds nothing. A node's own messages keep the order they were made in. - A message half taken in when its writer is removed is let go ((MQ-MEND)), not kept as if whole. - Smaller: a refused line no longer ends a waiting text 'Interrupted'; a node's own queued messages may be passed on by 16 nodes, not 15; no value is left on the stack when a port goes in mid-refusal. 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
380f1cc6ec
commit
2cf37aab4f
+71
-43
@@ -48,6 +48,21 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro
|
||||
\ structures. A definition that was under way stays hidden.
|
||||
: (RESET) 0 STATE a! ! (CG-RESET) CFBASE (CFP) a! ! ;
|
||||
|
||||
\ ( -- ) WHAT WAS PRINTED AND NOT SENT is put with the messages waiting,
|
||||
\ as a message of type 2 to where (PRINT-TO) says, by
|
||||
\ the port (PRINT-PORT): its characters four to a word, the first lowest.
|
||||
: (QUEUE-OUT)
|
||||
(OUT^) a! @ (OUT) - if NONE \ ( chars )
|
||||
dup 3 + 2/ 2/ (MQ#) a! @ + -MQ-ROOM + -if FULL drop
|
||||
(PRINT-TO) a! @ (MQ!) (ME) a! @ (MQ!) 2 (MQ!) 17 (MQ!) 0 (MQ!) 0 (MQ!)
|
||||
dup (MQ!) \ its length
|
||||
0 (PRINT-PORT) a! @ - (MQ!) \ the port, kept below zero: this node's own
|
||||
3 + 2/ 2/ -1 + push (OUT) \ ( at ) R: words - 1
|
||||
pop FOR dup a! @+ @+ 8* + @+ 8* 8* + @+ 8* 8* 8* + (MQ!) 4 + NEXT
|
||||
drop (OUT) (OUT^) a! ! ;
|
||||
NONE: drop ;
|
||||
FULL: drop drop (OUT) (OUT^) a! ! (LOST) a! @ 1 + ! ;
|
||||
|
||||
\ ( s -- ) the text is done with. What it printed is sent, then a message
|
||||
\ saying how it ended -- 0 QUIT, 1 completed, 2 an error -- and the node waits
|
||||
\ for the next. (DONE) is entered with the same number and, for an error,
|
||||
@@ -59,31 +74,29 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro
|
||||
\ and a stack fault in the middle of a pass would leave those messages in
|
||||
\ pieces. So a text that leaves more ends here in "Stack overflow", with
|
||||
\ the stack emptied, as a fault would end it.
|
||||
\ THE MESSAGE SAYING HOW IT ENDED is not written here: whoever sent the
|
||||
\ text may be stuck, and this node would wait on it. It is put with the
|
||||
\ messages waiting and passed on from (IDLE), as any message for another
|
||||
\ node is. It is put before the others, and this node does not begin
|
||||
\ THE MESSAGE SAYING HOW IT ENDED, AND WHAT THE TEXT PRINTED AND HAS NOT
|
||||
\ SENT, are not written here: whoever they are for, or a node on the way,
|
||||
\ may be stuck, and this node would wait on it. They are put with the
|
||||
\ messages waiting, (QUEUE-OUT) for what was printed, and passed on from
|
||||
\ (IDLE), as any message for another node is. With no room for one it
|
||||
\ is let go and counted. It is put before the others, and this node does not begin
|
||||
\ another text from the same sender until it has gone ((MINE?)): so what
|
||||
\ one sender is told comes in the order the texts were done.
|
||||
: (FINISH) ( s -- )
|
||||
DSTACK-DEPTH a! @ -30 + -if OVER drop \ what follows needs four cells of the stack: with
|
||||
1 (QUIET) a! ! \ from here an error is not this text's: see (RAISED)
|
||||
(LINE-STATUS) b! dup !b
|
||||
(FLUSH-OUT)
|
||||
1 (MQ#) a! @ + -MQ-ROOM + -if FULL \ how it ended goes with the messages waiting,
|
||||
(LINE-STATUS) a! !
|
||||
(MQ-MEND)
|
||||
(QUEUE-OUT) \ what the text printed, and then
|
||||
1 (MQ#) a! @ + -MQ-ROOM + -if FULL \ how it ended, go with the messages waiting,
|
||||
drop \ to be passed on as any is: (IDLE)
|
||||
(MQ#) a! @ push \ how many cells are there before it
|
||||
(MSG)+1 a! @ (MQ!) (ME) a! @ (MQ!) 3 (MQ!) \ to whoever sent the text, from this node, type 3
|
||||
0 (MQ!) 0 (MQ!) 0 (MQ!) 4 (MQ!) \ four characters long
|
||||
17 (MQ!) 0 (MQ!) 0 (MQ!) 4 (MQ!) \ sixteen nodes may pass it on; four characters long
|
||||
0 (DONE-PORT) a! @ - (MQ!) \ by the port that leads back, kept below zero: this node's own
|
||||
(MQ!) \ how it ended
|
||||
pop if FRONT -1 + FOR (MQ@) (MQ!) NEXT jump (IDLE) \ and those go round behind it: it is the oldest
|
||||
FRONT: drop jump (IDLE)
|
||||
OVER: drop 0 DSTACK-DEPTH a! ! jump (D-OVER) \ more left on it than may wait, the text ends in that error
|
||||
FULL: drop \ no room at all: it is offered here, and the node waits
|
||||
(MSG)+1 a! @ (DONE-PORT) a! @ (GATE)
|
||||
3 (HDR) 4 !b !b
|
||||
(LINE-STATUS) a! @ (MQ!) \ how it ended
|
||||
jump (IDLE)
|
||||
FULL: drop (LOST) a! @ 1 + ! jump (IDLE) \ no room at all: it is let go, and counted
|
||||
OVER: drop 0 DSTACK-DEPTH a! ! jump (D-OVER) \ more left on it than may wait, the text ends in that error
|
||||
|
||||
: (DONE)
|
||||
if GO -1 + if OK
|
||||
@@ -123,36 +136,47 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro
|
||||
\ ( -- flag ) IS THERE ONE FOR THIS NODE? The first that is, is taken
|
||||
\ out: its seven words into (MSG), the port it came on into (REPLY), its
|
||||
\ 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. 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.
|
||||
\ TEXT IS NOT BEGUN WHILE WHAT ITS SENDER IS OWED FROM AN EARLIER ONE IS
|
||||
\ STILL HERE: what that text printed, or how it ended -- a message of type
|
||||
\ 2 or 3 this node made itself, (FINISH). (NOTES) goes through the
|
||||
\ messages waiting first and notes whom each such message is to, in
|
||||
\ (PAY-K), which nothing else is using now; (A-WORD) is how many: as many
|
||||
\ as there are ports, and one that cannot be noted holds nothing back. A
|
||||
\ GONE this node is sending holds nothing back either, and a NACK or a
|
||||
\ GONE for this node is never held back.
|
||||
: (NOTES)
|
||||
0 (A-WORD) a! !
|
||||
(MQ#) a! @ (A-LEFT) a! !
|
||||
L: (A-LEFT) a! @ if END drop
|
||||
(MQ-NEXT)
|
||||
(MQ-HDR)+7 a! @ -if KEEP0
|
||||
drop (MQ-HDR)+2 a! @ -2 + if NOTE -1 + if NOTE drop jump KEEP
|
||||
NOTE: drop (A-WORD) a! @ -PORTS + -if KEEP0
|
||||
drop (MQ-HDR) a! @ push (A-WORD) a! @ dup 1 + ! (PAY-K) + a! pop !
|
||||
jump KEEP
|
||||
KEEP0: drop
|
||||
KEEP: (A-BACK) (A-TEXT) jump L
|
||||
END: drop ;
|
||||
|
||||
: (MINE?)
|
||||
0 (A-FOUND) a! ! 0 (A-WORD) a! !
|
||||
(NOTES)
|
||||
0 (A-FOUND) 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! @ -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
|
||||
(MQ-HDR)+7 a! @ -if THEIRS drop jump KEEP \ this node's own: to be passed on
|
||||
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! @ if TAKE0 \ no answer is waiting to go
|
||||
dup -PORTS + -1 + -if HOLD2 drop \ ( n count )
|
||||
(A-WORD) a! @ if TAKE0 \ nothing of this node's own is waiting to go
|
||||
(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
|
||||
drop jump TAKE \ none of it 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! !
|
||||
@@ -203,8 +227,10 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro
|
||||
|
||||
\ ( -- ) THE OFFER OF ONE WAS TAKEN, on the port (GATE-PORT) holds: the
|
||||
\ first of the messages waiting that goes by that port is the one. Its
|
||||
\ other words are written, each waiting for the neighbour, which has its
|
||||
\ first and reads to the end; and it is done with.
|
||||
\ other words are written, (!W), each waiting for the neighbour, which has
|
||||
\ its first and reads to the end; and it is done with. If the neighbour
|
||||
\ is removed meanwhile the rest is let go, and counted: no error comes of
|
||||
\ it, for an error here would leave the messages waiting in pieces.
|
||||
: (FWD-GO)
|
||||
0 (A-FOUND) a! !
|
||||
(MQ#) a! @ (A-LEFT) a! !
|
||||
@@ -215,15 +241,17 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro
|
||||
(FWD?) if KEEP1 drop
|
||||
(FWD-PORT) (GATE-PORT) a! @ xor if THIS drop jump KEEP
|
||||
KEEP1: drop jump KEEP
|
||||
THIS: drop 1 (A-FOUND) a! !
|
||||
(GATE-PORT) a! @ b!
|
||||
(MQ-HDR)+1 a! @ !b (MQ-HDR)+2 a! @ !b
|
||||
THIS: drop 1 (A-FOUND) a! ! (A-WORD) a! ! \ its words of text, kept off the stack
|
||||
0 (W-GONE) a! !
|
||||
(MQ-HDR)+1 a! @ (!W) (MQ-HDR)+2 a! @ (!W)
|
||||
(MQ-HDR)+3 a! @ if FRESH jump COUNT
|
||||
FRESH: drop 16
|
||||
COUNT: -1 + !b \ one fewer may pass it on
|
||||
(MQ-HDR)+4 a! @ !b (MQ-HDR)+5 a! @ !b (MQ-HDR)+6 a! @ !b
|
||||
if NOTEXT -1 + FOR (MQ@) !b NEXT jump L
|
||||
NOTEXT: drop jump L
|
||||
COUNT: -1 + (!W) \ one fewer may pass it on
|
||||
(MQ-HDR)+4 a! @ (!W) (MQ-HDR)+5 a! @ (!W) (MQ-HDR)+6 a! @ (!W)
|
||||
(A-WORD) a! @ if NOTEXT -1 + FOR (MQ@) (!W) NEXT jump SENT
|
||||
NOTEXT: drop
|
||||
SENT: (W-GONE) a! @ if WENT drop (LOST) a! @ 1 + ! jump L \ its reader was removed: the rest was let go
|
||||
WENT: drop jump L
|
||||
KEEP: (A-BACK) (A-TEXT) jump L
|
||||
END: drop ;
|
||||
|
||||
@@ -347,7 +375,7 @@ header NO-ROUTE
|
||||
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
|
||||
17 (MQ!) 0 (MQ!) 0 (MQ!) 4 (MQ!) \ sixteen nodes may pass it on; 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 ;
|
||||
@@ -568,7 +596,7 @@ header ABORT
|
||||
\ counted, and the node goes back to waiting.
|
||||
: (RAISED)
|
||||
(QUIET) a! @ if SPEAK
|
||||
drop (OUT) (OUT^) a! ! (LOST) a! @ 1 + ! jump (IDLE)
|
||||
drop (OUT) (OUT^) a! ! (LOST) a! @ 1 + ! (MQ-MEND) jump (IDLE)
|
||||
SPEAK: drop
|
||||
NODE-ERROR b! @b
|
||||
-if POS drop 2 jump (DONE)
|
||||
|
||||
Reference in New Issue
Block a user