fix(v4.0.0): what a node passes on waits with it, offered -- a relay is not held by a stuck node
Found after the last commit: a message being passed on toward a node that was stuck held the node passing it on in the wait, taking in what came but serving none of it; text typed for a stuck node left Hera deaf. And a node that had done text for a sender that then stuck waited on it to give its answer. A node with nothing to do now deals first with what is for itself; then offers at once the first message for each port and each refusal owed, and sleeps in the wait. What is taken is written and done with; the rest stays with the messages waiting, in order. How text ended is put with the messages waiting, not written from (FINISH). The stack is kept as shallow between lines as it was. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
482cc75faf
commit
1c720ab2c7
Binary file not shown.
+26
-23
@@ -182,7 +182,7 @@ header CMOVE
|
||||
\ messages in so as to be free to write, where it cannot begin a message
|
||||
\ of its own: so it notes what it owes, (OWE), in the eight pairs at
|
||||
\ (OWED) -- whom it is owed to, and the node the message was for -- and
|
||||
\ sends it when it next has nothing else to do, (PAY). With eight owed
|
||||
\ sends it when it next has nothing else to do, (PAY-SET). With eight owed
|
||||
\ already, one more is let go and counted. Nothing is owed for a NACK or
|
||||
\ for a GONE, type 5: there is no NACK for a NACK. The last 36 cells of
|
||||
\ the messages waiting are kept for those two types, so that ordinary
|
||||
@@ -303,13 +303,14 @@ header CMOVE
|
||||
16 !b 0 !b 0 !b ; \ how many nodes may pass it on (the TTL: MESH.md 7b); ACL tag; sequence
|
||||
|
||||
\ PAYING WHAT IS OWED (MESH.md 7c.3). Every refusal owed is offered at
|
||||
\ once, each on the port it goes by, one to a port, and the node sleeps in
|
||||
\ the wait: so one owed to a node that is stuck does not keep back one
|
||||
\ owed to a node that waits for it, and the node takes in whatever is
|
||||
\ written to it meanwhile. One there is no way for, or whose way is a
|
||||
\ once, each on the port it goes by, one to a port, with whatever the node
|
||||
\ has to pass on (quit.v4, (IDLE)), and the node sleeps in the wait: so
|
||||
\ one owed to a node that is stuck does not keep back one owed to a node
|
||||
\ that waits for it, and the node takes in whatever is written to it
|
||||
\ meanwhile. One there is no way for, or whose way is a
|
||||
\ port with nothing on it, is let go and counted first. (PAY-K) has a
|
||||
\ cell for each port: which refusal is offered there, counted from 1; 0,
|
||||
\ none.
|
||||
\ none; -1, a message being passed on.
|
||||
|
||||
\ ( k -- ) the k-th refusal owed is done with: the last takes its place
|
||||
: (PAID)
|
||||
@@ -327,30 +328,32 @@ header CMOVE
|
||||
|
||||
\ ( k -- ) offer the k-th refusal owed on its port, if nothing is there yet
|
||||
: (PAY-OFFER)
|
||||
dup 2* (OWED) + a! @ \ k to
|
||||
dup (PORT-FOR) (PORT) - \ k to n the port, by its number
|
||||
dup push 2* (OWED) + a! @ \ to R: k (the stack is kept shallow: this runs between lines)
|
||||
dup (PORT-FOR) (PORT) - \ to n the port, by its number
|
||||
dup (PAY-K) + a! @ if FREE
|
||||
drop drop drop drop ;
|
||||
drop drop drop pop drop ;
|
||||
FREE: drop
|
||||
dup push (OFFER) + a! ! \ k the message's first word, whom it is to
|
||||
1 + pop (PAY-K) + a! ! ;
|
||||
dup push (OFFER) + a! ! \ the message's first word, whom it is to
|
||||
pop pop 1 + SWAP (PAY-K) + a! ! ;
|
||||
|
||||
\ ( -- flag ) offer every refusal this node owes and wait once: if one
|
||||
\ is taken its other words are written and it is done with. Zero if
|
||||
\ nothing is owed, and then nothing was waited for.
|
||||
: (PAY)
|
||||
\ ( -- ) let go every refusal owed that cannot be sent; no port has an
|
||||
\ offer; then offer each that is left on its port
|
||||
: (PAY-SET)
|
||||
(OWED#) a! @ if NONE
|
||||
-1 + FOR pop dup push (PAY-DROP) NEXT
|
||||
(OWED#) a! @ if NONE
|
||||
(PAY-K) a! PORTS-1 FOR 0 !+ NEXT
|
||||
-1 + FOR pop dup push (PAY-OFFER) NEXT
|
||||
(OFFERS) if CAME
|
||||
drop (GATE-PORT) a! @ (PORT) - (PAY-K) + a! @ -1 + \ k: the one that was taken
|
||||
jump CLEAR
|
||||
NONE: drop
|
||||
CLEAR: (PAY-K) a! PORTS-1 FOR 0 !+ NEXT
|
||||
(OWED#) a! @ if NONE2
|
||||
-1 + FOR pop dup push (PAY-OFFER) NEXT ;
|
||||
NONE2: drop ;
|
||||
|
||||
\ ( k -- ) the offer of the k-th refusal owed was taken, and B is at the
|
||||
\ port: its other words are written, and it is done with
|
||||
: (PAY-GO)
|
||||
dup 2* (OWED) + 1 + a! @ \ k about
|
||||
4 (HDR) 4 !b !b \ from, type 4; four characters; about
|
||||
(PAID) -1 ;
|
||||
CAME: drop -1 ;
|
||||
NONE: drop 0 ;
|
||||
jump (PAID)
|
||||
|
||||
\ ( -- ) send what has been printed, to where (PRINT-TO) says, by the port
|
||||
\ (PRINT-PORT): its length, then its characters, four to a word, the first
|
||||
|
||||
+142
-43
@@ -54,12 +54,24 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro
|
||||
\ stops compiling first; it is always jumped to, never called, by
|
||||
\ something that has emptied the return stack (or by a fault, which empties
|
||||
\ it). (LINE-STATUS) keeps how the last text ended.
|
||||
\ 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.
|
||||
: (FINISH) ( s -- )
|
||||
1 (QUIET) a! ! \ from here an error is not this text's: see (RAISED)
|
||||
(LINE-STATUS) b! dup !b
|
||||
(FLUSH-OUT)
|
||||
(MSG)+1 a! @ (DONE-PORT) a! @ (GATE) \ to whoever sent the text
|
||||
3 (HDR) 4 !b !b \ a message of type 3, four characters long: how it ended
|
||||
1 (MQ#) a! @ + -MQ-ROOM + -if FULL \ how it ended goes with the messages waiting,
|
||||
drop \ to be passed on as any is: (IDLE)
|
||||
(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
|
||||
0 (DONE-PORT) a! @ - (MQ!) \ by the port that leads back, kept below zero: this node's own
|
||||
(MQ!) \ how it ended
|
||||
jump (IDLE)
|
||||
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
|
||||
jump (IDLE)
|
||||
|
||||
: (DONE)
|
||||
@@ -68,38 +80,144 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro
|
||||
OK: drop 1 jump (FINISH)
|
||||
GO: drop 0 jump (FINISH)
|
||||
|
||||
\ ( -- ) WAITING. A node with nothing to do deals with the oldest of the
|
||||
\ messages waiting (core.v4). With none waiting it is blocked reading its
|
||||
\ ports (docs/v4.0.0/MESH.md 4.1): it executes nothing until a neighbour
|
||||
\ writes, and what arrives is taken in as any message is, its first word
|
||||
\ from any port and the rest from the port that came on. The message's
|
||||
\ text goes into TIB, which holds 1024 characters, the most a message
|
||||
\ carries; one that came with a length no message has is error 12. A
|
||||
\ message of type 1 for this node is text to interpret: it is done as a
|
||||
\ line was, and (FINISH) reports how it ended. A message for another node
|
||||
\ is passed on, (PASS-ON).
|
||||
\ THE MESSAGES WAITING, GONE THROUGH. Three words below go through them
|
||||
\ all, as (A-QUEUE) does further down: each in turn is taken from the
|
||||
\ front, its eight cells into (MQ-HDR), and either used up or put at the
|
||||
\ back, so that those that stay are in the order they were in. (A-LEFT)
|
||||
\ is how many cells are still to be looked at, and (A-FOUND) what the pass
|
||||
\ has found.
|
||||
|
||||
\ ( -- n ) the next of them is in (MQ-HDR); n is how many words of text
|
||||
\ it has, which are still at the front
|
||||
: (MQ-NEXT)
|
||||
(A-HDR)
|
||||
(MQ-HDR)+6 a! @ -if SIZED drop 0 jump N
|
||||
SIZED: 3 + 2/ 2/
|
||||
N: (A-LEFT) a! @ over 8 + - ! ;
|
||||
|
||||
\ ( -- port | 0 ) the port the message in (MQ-HDR) goes by: for one this
|
||||
\ node made itself, (FINISH), the port kept with it, below zero; for any
|
||||
\ other, the way to the node it is for
|
||||
: (FWD-PORT)
|
||||
(MQ-HDR)+7 a! @ -if THEIRS 0 SWAP - ;
|
||||
THEIRS: drop (MQ-HDR) a! @ jump (PORT-FOR)
|
||||
|
||||
\ ( -- 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.
|
||||
: (MINE?)
|
||||
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) a! @ (ME) a! @ xor if MINE drop jump KEEP
|
||||
MINE: drop 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! !
|
||||
(MQ-HDR)+6 a! @ (MSG)+6 a! ! (MQ-HDR)+7 a! @ (REPLY) a! !
|
||||
TIB 2/ 2/ SWAP if EMPTY
|
||||
-1 + FOR (MQ@) over a! ! 1 + NEXT
|
||||
drop jump L
|
||||
EMPTY: drop drop jump L
|
||||
KEEP: (A-BACK) (A-TEXT) jump L
|
||||
END: drop (A-FOUND) a! @ ;
|
||||
|
||||
\ ( -- flag ) WHAT IS TO BE PASSED ON IS OFFERED (MESH.md 7c.3): for each
|
||||
\ message, the first for its port, its first word is offered there, unless
|
||||
\ a refusal owed is offered there already; (PAY-K) is set to -1 for that
|
||||
\ port. It stays with the messages waiting until the offer is taken.
|
||||
\ One that cannot go at all is let go, counted in (LOST), and whoever
|
||||
\ waits on it is told (core.v4, (TELL-OF)): one with no way known; one
|
||||
\ whose way is a port with nothing on it; and one that fifteen nodes have
|
||||
\ passed on already. The flag is not zero if any was let go.
|
||||
\ A MESSAGE IS PASSED ON BY AT MOST 16 NODES. Its fourth word says how
|
||||
\ many more may; 0, as a device sends it, is taken for 16.
|
||||
: (FWD-SET)
|
||||
0 (A-FOUND) a! !
|
||||
(MQ#) a! @ (A-LEFT) a! !
|
||||
L: (A-LEFT) a! @ if END drop
|
||||
(MQ-NEXT) (A-WORD) a! ! \ its words of text, kept off the stack: this runs between lines
|
||||
(MQ-HDR)+3 a! @ if FRESH jump COUNT
|
||||
FRESH: drop 16
|
||||
COUNT: -1 + if REFUSE drop
|
||||
(FWD-PORT) if REFUSE \ ( port )
|
||||
dup (THERE) if REFUSE2 drop
|
||||
(PORT) - dup (PAY-K) + a! @ if FREE \ ( p slot ) p: the port, by its number
|
||||
drop drop jump KEEP
|
||||
FREE: drop dup push (MQ-HDR) a! @ SWAP (OFFER) + a! ! \ whom it is to, offered
|
||||
-1 pop (PAY-K) + a! !
|
||||
KEEP: (A-BACK) (A-WORD) a! @ (A-TEXT) jump L
|
||||
REFUSE2: drop
|
||||
REFUSE: drop
|
||||
(A-WORD) a! @ if NOTEXT -1 + FOR (MQ@) drop NEXT jump TOLD
|
||||
NOTEXT: drop
|
||||
TOLD: (LOST) a! @ 1 + ! 1 (A-FOUND) a! !
|
||||
(MQ-HDR)+1 a! @ (MQ-HDR) a! @ (MQ-HDR)+2 a! @ (TELL-OF) jump L
|
||||
END: drop (A-FOUND) a! @ ;
|
||||
|
||||
\ ( -- ) 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.
|
||||
: (FWD-GO)
|
||||
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
|
||||
(FWD-PORT) (GATE-PORT) a! @ xor if THIS drop jump KEEP
|
||||
THIS: drop 1 (A-FOUND) a! !
|
||||
(GATE-PORT) a! @ b!
|
||||
(MQ-HDR)+1 a! @ !b (MQ-HDR)+2 a! @ !b
|
||||
(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
|
||||
KEEP: (A-BACK) (A-TEXT) jump L
|
||||
END: drop ;
|
||||
|
||||
\ ( -- ) WAITING. A node with nothing to do looks through the messages
|
||||
\ waiting (core.v4).
|
||||
\ ONE FOR THIS NODE is dealt with, the oldest first: (MINE?). A message
|
||||
\ of type 1 is text to interpret: it is done as a line was, and (FINISH)
|
||||
\ reports how it ended; one that came with a length no message has is
|
||||
\ error 12. A NACK is counted and a GONE from the node's centre believed.
|
||||
\ WITH NONE FOR IT, what it has for other nodes, and the refusals it owes,
|
||||
\ are offered, each on the port it goes by, and the node sleeps in the
|
||||
\ wait (MESH.md 7c): until one is taken, and then the rest of that one is
|
||||
\ written; or until a word comes for it, and then that message is taken in
|
||||
\ and it looks again. A node that is stuck never takes what is offered
|
||||
\ it, and holds up nothing else.
|
||||
\ WITH NOTHING WAITING AND NOTHING OWED it is blocked reading its ports
|
||||
\ (docs/v4.0.0/MESH.md 4.1): it executes nothing until a neighbour writes,
|
||||
\ and what arrives is taken in as any message is.
|
||||
: (IDLE)
|
||||
L: 1 (QUIET) a! ! \ nothing here is any text's doing: see (RAISED)
|
||||
(MQ#) a! @ if WAIT drop jump HAVE
|
||||
WAIT: drop (PAY) if BLOCK drop jump L \ what it owes is offered, and it sleeps (core.v4)
|
||||
(MINE?) if OTHERS drop jump HAVE
|
||||
OTHERS: drop
|
||||
(MQ#) a! @ (OWED#) a! @ + if BLOCK drop
|
||||
(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
|
||||
(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
|
||||
CAME: drop jump L
|
||||
BLOCK: drop (PORT)+8 b! @b (PORT)+9 b! @b (PORT) + dup b! \ ( to port ) B: the port it came on
|
||||
SWAP (TAKE) jump L
|
||||
HAVE:
|
||||
(MQ@) (MSG) a! ! (MQ@) (MSG)+1 a! ! (MQ@) (MSG)+2 a! ! (MQ@) (MSG)+3 a! !
|
||||
(MQ@) (MSG)+4 a! ! (MQ@) (MSG)+5 a! ! (MQ@) (MSG)+6 a! ! (MQ@) (REPLY) a! !
|
||||
(MSG)+6 a! @ -if SIZED
|
||||
drop 0 (MSG)+6 a! ! 0 SPAN a! ! NODE-ERROR b! 12 !b \ no telling what it was
|
||||
SIZED: drop
|
||||
TIB 2/ 2/ (MSG)+6 a! @ 3 + 2/ 2/ if EMPTY
|
||||
-1 + FOR (MQ@) over a! ! 1 + NEXT
|
||||
drop jump READ
|
||||
EMPTY: drop drop
|
||||
READ:
|
||||
0 (MSG)+6 a! @ TIB + C! \ a zero after the text
|
||||
(MSG)+6 a! @ SPAN a! !
|
||||
(MSG) a! @ (ME) a! @ xor if MINE drop jump (PASS-ON)
|
||||
MINE: drop
|
||||
(MSG)+2 a! @ -1 + if TEXT \ for this node, and
|
||||
(MSG)+2 a! @ -1 + if TEXT
|
||||
-3 + if NACK -1 + if GONE drop jump (IDLE) \ neither text nor these: let go
|
||||
NACK: drop (REFUSED) a! @ 1 + ! jump (IDLE) \ a message of this node's was refused: counted
|
||||
GONE: drop (MSG)+6 a! @ -4 + if G4 drop jump (IDLE) \ a node is gone, if its centre says so:
|
||||
@@ -118,25 +236,6 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro
|
||||
Q1: (PRINT-PORT) a! !
|
||||
jump (LINE)
|
||||
|
||||
\ ( -- ) A MESSAGE FOR ANOTHER NODE is passed on (MESH.md section 7): all
|
||||
\ of it, as it came, to the port that leads toward that node. With no way
|
||||
\ known it is let go, and (LOST) counts it.
|
||||
: (PASS-ON)
|
||||
(MSG)+3 a! @ if FRESH jump COUNT \ how many more nodes may pass it on;
|
||||
FRESH: drop 16 \ from a device, which set none: sixteen
|
||||
COUNT: -1 + if SPENT (MSG)+3 a! !
|
||||
(MSG) a! @ (PORT-FOR) if NOWAY
|
||||
dup (THERE) if NOONE drop
|
||||
(MSG) a! @ SWAP (GATE) (MSG)+1 a! 5 FOR @+ !b UNEXT \ its seven words
|
||||
(MSG)+6 a! @ 3 + 2/ 2/ if SENT
|
||||
-1 + TIB 2/ 2/ a! FOR @+ !b UNEXT \ and its text
|
||||
jump (IDLE)
|
||||
SENT: drop jump (IDLE)
|
||||
NOONE: drop \ its way is a port with nothing on it
|
||||
SPENT: \ it has been passed on as often as it may be
|
||||
NOWAY: drop (LOST) a! @ 1 + !
|
||||
(MSG)+1 a! @ (MSG) a! @ (MSG)+2 a! @ (TELL-OF) jump (IDLE) \ whoever waits on it is told (core.v4)
|
||||
|
||||
\ ( -- ) THE TEXT, INTERPRETED. It is in TIB with a zero after it and its
|
||||
\ length in SPAN, and the return stack is empty. It is interpreted with one
|
||||
\ return entry under it, this word's call of INTERPRET; whatever is on the
|
||||
|
||||
@@ -398,6 +398,13 @@ int main(void)
|
||||
CHECK(is_empty(tell(10, "66 NO-ROUTE")) && waiting(hera) && waiting(mid) && waiting(far), "the way is forgotten, and all three are at rest");
|
||||
}
|
||||
|
||||
/* ---- what a node passes on keeps its order, however long it must be kept (MESH.md 7c) ---- */
|
||||
CHECK(is_empty(tell(11, "12 2 ROUTE")), "node 11 is told the way to node 12 is by node 10");
|
||||
CHECK(is_empty(tell(12, ": SLOW 30000 0 DO LOOP ;")), "node 12 is given a word that takes a while");
|
||||
CHECK(strcmp(tell(11, ": TRIO S\" SLOW 68 EMIT\" 12 SEND S\" 69 EMIT\" 12 SEND S\" 70 EMIT\" 12 SEND ; TRIO"), "DEF") == 0,
|
||||
"it sends node 12 three texts, the first slow to do: node 10 keeps the other two until node 12 reads again, and they are done in order: \"%s\"", printed);
|
||||
CHECK(is_empty(tell(11, "12 3 ROUTE")) && waiting(hera) && waiting(mid) && waiting(far) && pool[0].n.mem[MQ_COUNT] == 0, "the way is told again; all three are at rest, keeping nothing");
|
||||
|
||||
/* ---- a node that is stuck holds up no one (MESH.md 7c) ------------------- */
|
||||
v4_fabric_gone_error(&f, V4_ERROR_NO_ONE);
|
||||
|
||||
@@ -406,7 +413,7 @@ int main(void)
|
||||
|
||||
/* a refusal owed to a stuck node whose number is the lower */
|
||||
CHECK(is_empty(said(12, "NO-ROUTES 1 3 ROUTE 10 3 ROUTE 11 2 ROUTE")) && is_empty(said(11, "55 3 ROUTE")), "node 12 has no way for 55; node 11 is told the way to 55 is by node 12");
|
||||
CHECK(strcmp(tell(11, ": C1 S\" 1 DROP\" 55 SEND BEGIN 0 UNTIL ; C1"), "(still running)") == 0, "node 11 sends 55 a message and is then stuck in a loop");
|
||||
CHECK(strcmp(tell(11, ": C1 S\" 1 DROP\" 55 SEND S\" 1 DROP\" 12 SEND BEGIN 0 UNTIL ; C1"), "(still running)") == 0, "node 11 sends 55 a message, and node 12 text, and is then stuck in a loop");
|
||||
CHECK(pool[2].n.mem[OWED_COUNT] == 1, "node 12 owes node 11 a refusal, and cannot give it: node 11 is not reading");
|
||||
CHECK(strcmp(said(12, "7 8 * ."), "56 ") == 0 && printed_from == 12, "node 12 goes on doing what it is sent: \"%s\"", printed);
|
||||
{
|
||||
@@ -423,6 +430,18 @@ int main(void)
|
||||
"node 10 sends 77 a message and waits: node 12, which still owes the stuck node, tells node 10 it was refused: \"%s\"", printed);
|
||||
CHECK(is_empty(said(10, "77 NO-ROUTE")), "the way is forgotten");
|
||||
|
||||
/* a message passed on toward the stuck node waits with the node passing it on, which goes on serving */
|
||||
{
|
||||
v4_cell kept = pool[0].n.mem[MQ_COUNT];
|
||||
CHECK(is_empty(said(11, "1 DROP")) && ended == 0 && pool[0].n.mem[MQ_COUNT] > kept && v4_node_in_wait(&pool[0].n),
|
||||
"text from the console for the stuck node comes to node 10, which cannot hand it on: it keeps it, offered, and sleeps");
|
||||
CHECK(strcmp(said(10, "1 2 + ."), "3 ") == 0 && strcmp(said(12, "7 8 * ."), "56 ") == 0 && printed_from == 12,
|
||||
"node 10 goes on doing what it is sent, and passing on what is for others: \"%s\"", printed);
|
||||
CHECK(pool[0].n.mem[MQ_COUNT] > kept && v4_node_in_wait(&pool[0].n), "still keeping what is for the stuck node");
|
||||
}
|
||||
/* the stuck node's own answer: node 12 did text node 11 sent before it stuck, and cannot give it the answer */
|
||||
CHECK(pool[2].n.mem[MQ_COUNT] > 0 && v4_node_in_wait(&pool[2].n), "node 12 keeps the answer it has for node 11, offered, and sleeps");
|
||||
|
||||
/* a line that must begin a message to the stuck node waits, and the node takes in what comes */
|
||||
CHECK(is_empty(said(10, ": TO11 S\" 1 DROP\" 11 SEND 65 EMIT ; TO11")) && ended == 0 && v4_node_in_wait(&pool[0].n) && !pool[0].n.asking,
|
||||
"node 10 sends the stuck node a message: its line waits in the wait, not blocked writing");
|
||||
@@ -447,8 +466,8 @@ int main(void)
|
||||
CHECK(strstr(printed, "No one on that port") != NULL && strstr(printed, "A") == NULL && ended == 1, "the line ends in an error that says no one is there: \"%s\"", printed);
|
||||
}
|
||||
step_cap = 20000000;
|
||||
CHECK(strcmp(said(12, "7 8 * ."), "56 ") == 0 && pool[2].n.mem[OWED_COUNT] == 0 && waiting(far) && !v4_node_in_wait(&pool[2].n) && waiting(hera),
|
||||
"node 12 goes on, the refusal it owed node 11 let go: it owes nothing and is at rest");
|
||||
CHECK(strcmp(said(12, "7 8 * ."), "56 ") == 0 && pool[2].n.mem[OWED_COUNT] == 0 && pool[2].n.mem[MQ_COUNT] == 0 && pool[0].n.mem[MQ_COUNT] == 0 && waiting(far) && !v4_node_in_wait(&pool[2].n) && waiting(hera),
|
||||
"node 12 goes on; what it owed node 11 and kept for it, and what node 10 kept for it, are let go: they owe and keep nothing, and are at rest");
|
||||
|
||||
/* a refusal owed to a stuck node whose number is the higher */
|
||||
step_cap = 3000000;
|
||||
|
||||
@@ -63,7 +63,7 @@ static v4_heat h;
|
||||
static v4_text tx;
|
||||
static v4_cell w_key, w_key_end, w_fault, capsule_latest;
|
||||
static v4_cell w_idle; /* (IDLE): where the node waits for a message */
|
||||
static v4_cell w_idle_end; /* (PASS-ON): the word after it */
|
||||
static v4_cell w_idle_end; /* (LINE): the word after it */
|
||||
static char out[V4_CONSOLE_CAP + 1];
|
||||
|
||||
/* STORAGE (MESH.md section 8). The node asks its kernel for its blocks, and
|
||||
@@ -871,7 +871,7 @@ int main(void)
|
||||
printf(" capsule: %ld words\n", (long)v4_text_here(&tx) - 16);
|
||||
if (failures) { printf(" %d checks, %d failures\n", checks, failures); return 1; }
|
||||
w_idle = v4_text_word(&tx, "(IDLE)");
|
||||
w_idle_end = v4_text_word(&tx, "(PASS-ON)"); /* the word after (IDLE) in quit.v4 */
|
||||
w_idle_end = v4_text_word(&tx, "(LINE)"); /* the word after (IDLE) in quit.v4 */
|
||||
w_key = v4_text_word(&tx, "KEY");
|
||||
w_key_end = v4_text_word(&tx, "CR"); /* the word after KEY in core.v4 */
|
||||
w_fault = v4_text_word(&tx, "(FAULTS)");
|
||||
|
||||
@@ -530,7 +530,16 @@ int main(void)
|
||||
CHECK(strcmp(tell(13, ": SPIN BEGIN 0 UNTIL ; SPIN"), "(still running)") == 0, "node 13 is stuck in a loop");
|
||||
CHECK(strcmp(tell(12, ": W13 13 AWAIT . ; W13"), "(still running)") == 0 && node_numbered(12)->mem[AWAIT_FROM] == 13 && waiting(12),
|
||||
"node 12, which is not wired to it, waits for its answer");
|
||||
/* while it is stuck it holds up no one (MESH.md 7c): text for it waits with Hera, who goes on */
|
||||
(void)tell(13, "1 DROP");
|
||||
CHECK(ended == 0 && v4_node_in_wait(node_numbered(10)) && !node_numbered(10)->asking && node_numbered(10)->mem[MQ_COUNT] > 0,
|
||||
"text typed for the stuck node waits with Hera, offered: she sleeps in the wait, not blocked writing");
|
||||
(void)tell(11, "11 100 * .");
|
||||
CHECK(strcmp(printed, "1100 ") == 0 && ended == 1, "text typed for another node is passed on and done meanwhile: \"%s\"", printed);
|
||||
(void)tell(10, "1 2 + .");
|
||||
CHECK(strcmp(printed, "3 ") == 0 && ended == 1, "and so is text for Hera herself: \"%s\"", printed);
|
||||
(void)tell(10, "13 KILL");
|
||||
CHECK(node_numbered(10)->mem[MQ_COUNT] == 0, "killing it, she lets go what she kept for it");
|
||||
CHECK(node_numbered(13) == NULL && strstr(printed, "Node gone") != NULL && node_numbered(12)->mem[AWAIT_FROM] == 0 && waiting(12),
|
||||
"Hera kills node 13: node 12's wait ends, with an error that says the node is gone: \"%s\"", printed);
|
||||
step_limit = 30000000ul;
|
||||
|
||||
Reference in New Issue
Block a user