fix(v4.0.0): 29 values left on the stack hung the node; and what the review of step 6d found
The review of step 6d found it not sound. Mended here, with a check that failed first: a text that left 29 values on the stack hung the node for ever, on the products too -- the passes over the messages waiting that follow every text need four cells, and a stack fault in the middle of one left the messages in pieces. Such a text ends 'Stack overflow', as before step 6d. hosted-check types it. The other findings are open and are written under step 6d in MESH.md section 10; the README no longer says the aim is met. make -C v4 test and sanitize at both widths, hosted-check. The bare metal boots have not been made again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
2b587206ee
commit
380f1cc6ec
Binary file not shown.
@@ -1256,6 +1256,37 @@ Each is tested, committed and pushed before the next.
|
||||
`hosted-check`, lint; three bare-metal boots, `logs/20261008-011558`
|
||||
(amd64), `-011833` (aarch64), `-012159` (riscv64). On all six: POST
|
||||
538 of 538, `word_count=317`, `dict_hash=0x6a39c0bb9d183418`.
|
||||
- **The review (2026-10-08) found the step not sound as built.** One
|
||||
finding is mended, the rest are open and the claims of 7b and 7c that
|
||||
"a stuck node holds up no other" are not yet true in the cases below.
|
||||
- *Mended.* A line that left 29 values on the stack hung the node for
|
||||
ever, on the products too: the passes over the messages waiting
|
||||
that now follow every text need four cells, and a stack fault in
|
||||
the middle of one left the messages in pieces. Such a text now
|
||||
ends "Stack overflow", as it did before step 6d
|
||||
(`test_host_quit.c`; `hosted-check`). The boots above were made
|
||||
before this and do not show it.
|
||||
- *Open: a node removed while a message is being passed on to it*
|
||||
leaves the node passing it on going round for ever: the error
|
||||
comes in the middle of writing the message out of the messages
|
||||
waiting, and leaves them in pieces.
|
||||
- *Open: offers left standing.* When a node lets a message go and
|
||||
then begins text without having slept, what it had offered is
|
||||
still offered, and the text's own message can go to the wrong
|
||||
port. The review saw text meant for one node done by another.
|
||||
- *Open: what a finished text printed* is still begun as a message
|
||||
from text is, and if the way to the console is through a stuck
|
||||
node the node is held and cannot be typed to.
|
||||
- *Open: with more than eight messages of its own waiting* (answers,
|
||||
or the GONEs of `KILL`) a node begins no text at all; on Hera that
|
||||
cannot be undone from the console.
|
||||
- *Open, smaller:* an error while a refusal is being written leaves
|
||||
a value on the stack; with no room at all, how text ended is
|
||||
begun as a message and can be held by a stuck sender; a line that
|
||||
was itself refused for want of room can still end a waiting text
|
||||
"Interrupted"; a message a node makes itself may be passed on by
|
||||
15 nodes, not 16; the flood's figures in 7a are stale (278 arrive
|
||||
now) and `(LOST)` counts some messages more than once.
|
||||
|
||||
7. **A second unit; scaling while running; sleep, wake and kill by
|
||||
command.**
|
||||
|
||||
@@ -202,6 +202,8 @@ hosted-check: $(foreach i,$(HOSTED_ISAS),$(BINDIR)/boot-$(i).txt) $(BINDIR)/star
|
||||
@grep -q '^ok> No one on that port$$' $(BINDIR)/noone-amd64.txt && grep -q '^ok> 3 ok$$' $(BINDIR)/noone-amd64.txt || { echo "hosted-check: a write to a port with no one on it was not an error the node came back from"; cat $(BINDIR)/noone-amd64.txt | tail -4; exit 1; }
|
||||
@printf '5 AWAIT\n1 2 + .\n7 8 * .\n' | $(BINDIR)/starforth4-amd64 > $(BINDIR)/await-amd64.txt 2>&1; true
|
||||
@grep -q '^ok> Interrupted$$' $(BINDIR)/await-amd64.txt && grep -q '^ok> 3 ok$$' $(BINDIR)/await-amd64.txt && grep -q '^ok> 56 ok$$' $(BINDIR)/await-amd64.txt || { echo "hosted-check: a line typed while the node waited did not break the wait and then run"; tail -6 $(BINDIR)/await-amd64.txt; exit 1; }
|
||||
@printf '1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29\n1 2 + .\n' | $(BINDIR)/starforth4-amd64 > $(BINDIR)/deep-amd64.txt 2>&1; true
|
||||
@grep -q '^ok> Stack overflow$$' $(BINDIR)/deep-amd64.txt && grep -q '^ok> 3 ok$$' $(BINDIR)/deep-amd64.txt || { echo "hosted-check: a line that left 29 values on the stack was not an error the node came back from"; tail -4 $(BINDIR)/deep-amd64.txt; exit 1; }
|
||||
@$(BINDIR)/starforth4-postfail < /dev/null > $(BINDIR)/postfail.txt; test $$? -ne 0 || { echo "hosted-check: a boot with a failing case did not fail"; exit 1; }
|
||||
@grep -q '^POST FAIL: fail.wrong out<5 5 $$' $(BINDIR)/postfail.txt || { echo "hosted-check: the failing case was not named"; cat $(BINDIR)/postfail.txt; exit 1; }
|
||||
@grep -q '^POST FAIL: fail.many out<QQQQ' $(BINDIR)/postfail.txt || { echo "hosted-check: the case that prints too much was not named"; exit 1; }
|
||||
|
||||
+4
-3
@@ -146,9 +146,10 @@ is gone; a node believes that only from its centre.
|
||||
**The wait** (`MESH.md` 7c, step 6d). A node does not write the first word
|
||||
of a message: it offers it, and sleeps until it is taken or a word comes
|
||||
for it. What a node has to pass on, the answers it has to give and the
|
||||
refusals it owes all wait with it, offered, and go when they can. So a
|
||||
node that is stuck holds up no other: only text that must itself send to
|
||||
the stuck node waits, and on Hera a typed line ends that.
|
||||
refusals it owes all wait with it, offered, and go when they can. The aim
|
||||
is that a node that is stuck holds up no other. **It is not yet met in
|
||||
every case:** the review of step 6d found several where a node is still
|
||||
held or goes wrong, listed under step 6d in `MESH.md` section 10.
|
||||
|
||||
**Blocks** (`MESH.md` step 6). The block words are the kernel's, as they
|
||||
are for a v3 VM: `BLOCK`, `BUFFER`, `UPDATE`, `SAVE-BUFFERS` and
|
||||
|
||||
@@ -54,6 +54,11 @@ 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.
|
||||
\ A TEXT MAY LEAVE 28 VALUES ON THE STACK. What a node does between texts
|
||||
\ -- (IDLE)'s passes over the messages waiting -- needs four cells of it,
|
||||
\ 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
|
||||
@@ -61,6 +66,7 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro
|
||||
\ 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)
|
||||
@@ -73,6 +79,7 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro
|
||||
(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
|
||||
|
||||
@@ -1134,6 +1134,21 @@ int main(void)
|
||||
}
|
||||
printf(" %u values may wait on the stack while the next line is typed and interpreted\n", most);
|
||||
CHECK(most + 4u >= V4_DATA_DEPTH, "the prompt and the interpreter take no more than four cells of the stack");
|
||||
/* one more than may wait: the line ends in an error that says so, and the node goes on (found by the review of step 6d) */
|
||||
{
|
||||
char line[4 * V4_DATA_DEPTH + 16];
|
||||
size_t at = 0;
|
||||
unsigned m;
|
||||
const char *r;
|
||||
boot_bare();
|
||||
for (m = 0; m < most + 1; m++) at += (size_t)snprintf(line + at, sizeof line - at, "1 ");
|
||||
snprintf(line + at, sizeof line - at, "\n");
|
||||
r = say(line);
|
||||
CHECK(strstr(r, "Stack overflow") != NULL && strstr(r, " ERROR\nok> ") != NULL, "a line that leaves one value more than may wait ends in an error that says so: \"%s\"", r);
|
||||
CHECK(strcmp(say("1 2 + .\n"), "3 ok\nok> ") == 0, "and the next line is done as usual");
|
||||
for (m = 0; m < 2000 && !node_idle(); m++) (void)v4_exec_step_word(&n, &es, &h); /* it finishes what it was doing when its answer went */
|
||||
CHECK(n.mem[MQ_COUNT] == 0 && node_idle(), "with nothing left among the messages waiting, and the node at its ports");
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- how much of the data stack a line has ---- */
|
||||
|
||||
Reference in New Issue
Block a user