feat(v4.0.0): messages are whole and wait on the wire -- a node keeps none but the one it is doing
Step 6e, tasks 2 and 3 (docs/v4.0.0/MESH.md 7d). The nucleus puts, looks at, takes, moves and drops whole messages through the six addresses after its ports; its own ring of messages waiting, the refusals owed, (GATE) and the looking words' use are gone. SEND, an answer, a NACK and a GONE go or are refused at once; what a text prints waits for room; a text is not begun until the wire its answer goes by has room for it, and that room is kept. The lone node's host (v4/system/boot.c) keeps its two wires and does its operations; the test hosts' consoles put and take whole messages through the fabric. New: tests/test_host_depth.c, every message path of a mesh node at every depth of both stacks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
83694b18be
commit
b1d09af043
+104
-74
@@ -63,6 +63,8 @@ static int storage_made(void)
|
||||
}
|
||||
static v4_place places[PLACES];
|
||||
static v4_fabric f;
|
||||
#define QUEUES 64u /* two for every wire there is at once: five kernels, the console, four to Hera, four round the square */
|
||||
static v4_wire_queue queues[QUEUES];
|
||||
static v4_image im; /* only what the dictionary hash needs of it */
|
||||
|
||||
/* ---- the capsules ---- */
|
||||
@@ -196,10 +198,10 @@ static int kernel_take(void *self, v4_cell value) /* a request */
|
||||
}
|
||||
static const v4_device kernel = { kernel_take, kernel_give, 0, 0 };
|
||||
|
||||
/* ---- the console: a device on Hera's port 1 ---- */
|
||||
/* ---- the console: a device on Hera's port 1 ----
|
||||
* It speaks whole messages: it puts them on the wire to Hera and takes them
|
||||
* off the wire from her, through the fabric (MESH.md 7d.2). */
|
||||
#define CONSOLE_ID 1
|
||||
static v4_message going, coming;
|
||||
static unsigned going_at;
|
||||
static char printed[8192]; /* what has come back since the console last sent */
|
||||
static unsigned printed_len;
|
||||
static v4_cell printed_from;
|
||||
@@ -207,48 +209,45 @@ static int ended;
|
||||
static v4_cell ended_from, ended_how;
|
||||
static unsigned post_passed[32]; /* by node number: POST tallies with no failures seen from it */
|
||||
static unsigned post_other; /* tallies with failures */
|
||||
static const v4_device console = { 0, 0, 0, 0 };
|
||||
|
||||
static int console_give(void *self, v4_cell *value)
|
||||
static unsigned console_takes(void)
|
||||
{
|
||||
(void)self;
|
||||
if (going_at >= going.count) return 0;
|
||||
*value = going.word[going_at++];
|
||||
return 1;
|
||||
}
|
||||
static int console_take(void *self, v4_cell value)
|
||||
{
|
||||
(void)self;
|
||||
if (v4_message_word(&coming, value)) {
|
||||
if (v4_message_type(&coming) == V4_MSG_OUTPUT) {
|
||||
unsigned i, chars = v4_message_length(&coming), start = printed_len;
|
||||
for (i = 0; i < chars && printed_len + 1 < sizeof printed; i++) printed[printed_len++] = v4_message_char(&coming, i);
|
||||
static v4_cell hd[V4_WIRE_HEADER], text[V4_MSG_MAX_CHARS / 4u];
|
||||
unsigned took = 0;
|
||||
while (v4_fabric_device_take(&f, hera_place, 1, hd, text, V4_MSG_MAX_CHARS / 4u) == V4_WIRE_DONE) {
|
||||
took++;
|
||||
if (hd[2] == V4_MSG_OUTPUT) {
|
||||
unsigned i, start = printed_len;
|
||||
for (i = 0; i < (unsigned)hd[6] && printed_len + 1 < sizeof printed; i++) printed[printed_len++] = (char)(((v4_ucell)text[i / 4u] >> (8u * (i % 4u))) & 0xFFu);
|
||||
printed[printed_len] = 0;
|
||||
printed_from = v4_message_from(&coming);
|
||||
printed_from = hd[1];
|
||||
if (strstr(printed + start, "PARITY:V4_POST")) {
|
||||
if (strstr(printed + start, " fail=0\n") && printed_from >= 0 && printed_from < 32) post_passed[printed_from]++;
|
||||
else post_other++;
|
||||
}
|
||||
} else if (v4_message_type(&coming) == V4_MSG_DONE) {
|
||||
} else if (hd[2] == V4_MSG_DONE) {
|
||||
ended++;
|
||||
ended_from = v4_message_from(&coming);
|
||||
ended_how = coming.word[V4_MSG_HEADER];
|
||||
ended_from = hd[1];
|
||||
ended_how = text[0];
|
||||
}
|
||||
coming.count = 0;
|
||||
}
|
||||
return 1;
|
||||
return took;
|
||||
}
|
||||
static int console_pending(void *self) { (void)self; return going_at < going.count; }
|
||||
static const v4_device console = { console_take, console_give, 0, console_pending };
|
||||
|
||||
/* Is there a node that will execute at the next step? A step in which a
|
||||
* node only faulted counts nothing done (exec.h), and it goes on from its
|
||||
* fault handler at the next. */
|
||||
/* Is there a node, other than those known to be going round for ever, that
|
||||
* will execute at the next step? A node asleep at a wire will not; a step
|
||||
* in which a node only faulted counts nothing done (exec.h), and it goes on
|
||||
* from its fault handler at the next. */
|
||||
static unsigned spinning; /* bit n: the node numbered n is known to be stuck in a loop, and is not waited for */
|
||||
static int any_running(void)
|
||||
{
|
||||
unsigned k;
|
||||
for (k = 0; k < PLACES; k++) {
|
||||
const v4_fabric_node *x = v4_fabric_node_at(&f, k);
|
||||
if (x && !places[k].asleep && !x->n.stopped && !x->n.asking && !(x->n.reading && !x->n.given)) return 1;
|
||||
if (!x || places[k].asleep || x->n.stopped || x->n.asking || x->n.doing || (x->n.reading && !x->n.given)) continue;
|
||||
if (x->n.mem[ME] >= 0 && x->n.mem[ME] < 32 && (spinning & 1u << x->n.mem[ME])) continue;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -260,21 +259,31 @@ static void stuck(void)
|
||||
unsigned k;
|
||||
for (k = 0; k < PLACES; k++) {
|
||||
const v4_fabric_node *x = v4_fabric_node_at(&f, k);
|
||||
if (x) printf(" stuck: node %ld p=%ld asking=%d port=%u reading=%d rport=%u given=%d stopped=%d mq=%ld lost=%ld\n", (long)x->n.mem[ME], (long)x->n.p,
|
||||
x->n.asking, x->n.ask_port, x->n.reading, x->n.read_port, x->n.given, x->n.stopped, (long)x->n.mem[MQ_COUNT], (long)x->n.mem[LOST]);
|
||||
if (x) printf(" stuck: node %ld p=%ld asking=%d port=%u reading=%d doing=%d op=%ld wire=%u stopped=%d await=%ld lost=%ld\n", (long)x->n.mem[ME], (long)x->n.p,
|
||||
x->n.asking, x->n.ask_port, x->n.reading, x->n.doing, (long)x->n.do_op, x->n.wire, x->n.stopped, (long)x->n.mem[AWAIT_FROM], (long)x->n.mem[LOST]);
|
||||
}
|
||||
}
|
||||
/* Send text to a node and let everything that follows from it happen. */
|
||||
/* Send text to a node and let everything that follows from it happen: until
|
||||
* nothing can; or, with nodes known to be stuck, until no other node has
|
||||
* executed and the console has been sent nothing for a while. */
|
||||
static const char *tell(v4_cell node, const char *text)
|
||||
{
|
||||
unsigned long steps = 0;
|
||||
static v4_message m;
|
||||
unsigned long steps = 0, quiet = 0;
|
||||
printed_len = 0; printed[0] = 0; printed_from = -1;
|
||||
ended = 0; ended_from = -1; ended_how = -1;
|
||||
if (!v4_message_text(&going, node, CONSOLE_ID, V4_MSG_TEXT, text, (unsigned)strlen(text))) return "(too long)";
|
||||
going_at = 0;
|
||||
while (steps < step_limit && (v4_fabric_step(&f) != 0 || any_running())) steps++;
|
||||
if (steps >= step_limit) { stuck(); return "(still running)"; }
|
||||
return printed;
|
||||
if (!v4_message_text(&m, node, CONSOLE_ID, V4_MSG_TEXT, text, (unsigned)strlen(text))) return "(too long)";
|
||||
if (v4_fabric_device_put(&f, hera_place, 1, m.word, m.word + V4_MSG_HEADER) != V4_WIRE_DONE) return "(not put)";
|
||||
while (steps < step_limit) {
|
||||
unsigned did = v4_fabric_step(&f), took = console_takes();
|
||||
int run = any_running();
|
||||
steps++;
|
||||
if (did == 0 && took == 0 && !run) return printed;
|
||||
quiet = (spinning && !run && took == 0) ? quiet + 1 : 0;
|
||||
if (quiet >= 400000ul) return printed;
|
||||
}
|
||||
stuck();
|
||||
return "(still running)";
|
||||
}
|
||||
static int told(v4_cell node, const char *text) { return tell(node, text)[0] == 0 && ended == 1 && ended_how == V4_TEXT_COMPLETED; }
|
||||
|
||||
@@ -314,7 +323,7 @@ static unsigned load(v4_cell node, const char *file)
|
||||
while ((n = next_line(&r, line)) >= 0) {
|
||||
line[n] = 0;
|
||||
(void)tell(node, line);
|
||||
if (ended != 1 || ended_how != V4_TEXT_COMPLETED) { if (!bad) { const v4_node *q = &pool[0].n; printf(" %s: \"%s\" -> \"%s\" ended=%d how=%ld; stopped=%d asking=%d port=%u reading=%d rport=%u p=%ld fault=%u@%ld\n", file, line, printed, ended, (long)ended_how, q->stopped, q->asking, q->ask_port, q->reading, q->read_port, (long)q->p, q->fault_kind, (long)q->fault_addr); } bad++; }
|
||||
if (ended != 1 || ended_how != V4_TEXT_COMPLETED) { if (!bad) { const v4_node *q = &pool[0].n; printf(" %s: \"%s\" -> \"%s\" ended=%d how=%ld; stopped=%d asking=%d port=%u doing=%d op=%ld p=%ld fault=%u@%ld\n", file, line, printed, ended, (long)ended_how, q->stopped, q->asking, q->ask_port, q->doing, (long)q->do_op, (long)q->p, q->fault_kind, (long)q->fault_addr); } bad++; }
|
||||
}
|
||||
return bad;
|
||||
}
|
||||
@@ -331,10 +340,18 @@ static v4_uheat_t clock_of(v4_cell number)
|
||||
for (k = 0; k < PLACES; k++) if (v4_fabric_node_at(&f, k) && v4_fabric_node_at(&f, k)->n.mem[ME] == number) return v4_fabric_node_at(&f, k)->es.anticlock;
|
||||
return 0;
|
||||
}
|
||||
/* 1 if the node is asleep (operation 8): it executes nothing until a message comes. */
|
||||
static int waiting(v4_cell number)
|
||||
{
|
||||
const v4_node *n = node_numbered(number);
|
||||
return n && n->reading && !n->given && n->read_port == V4_PORT_ANY;
|
||||
return n && n->doing && n->do_op == 8;
|
||||
}
|
||||
/* how many cells of messages wait on the wire going from a port of the node */
|
||||
static unsigned going_from(v4_cell number, unsigned port)
|
||||
{
|
||||
unsigned k;
|
||||
for (k = 0; k < PLACES; k++) if (v4_fabric_node_at(&f, k) && v4_fabric_node_at(&f, k)->n.mem[ME] == number && places[k].wire[port].tx) return places[k].wire[port].tx->used;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
@@ -381,18 +398,17 @@ int main(void)
|
||||
|
||||
/* ---- Hera is born empty, and takes in the nucleus ---- */
|
||||
v4_fabric_init(&f, places, PLACES);
|
||||
v4_fabric_queues(&f, queues, QUEUES);
|
||||
v4_fabric_gone_error(&f, V4_ERROR_NO_ONE);
|
||||
v4_fabric_interrupt_error(&f, V4_ERROR_INTERRUPTED);
|
||||
place = host_born(0);
|
||||
CHECK(place == 0, "a node is born");
|
||||
hera_place = (unsigned)place;
|
||||
for (i = 0; i < 4096 && pool[0].n.mem[i] == 0; i++) { }
|
||||
CHECK(i == 4096 && pool[0].n.p == PORT + (v4_cell)V4_PORT_ANY, "with nothing in it, listening at its ports");
|
||||
CHECK(v4_fabric_wire_device(&f, hera_place, 0, &kernel) && v4_fabric_wire_device(&f, hera_place, 1, &console), "the kernel is on its port 0 and the console on its port 1");
|
||||
going.count = 0; going_at = 0;
|
||||
for (i = 0; i < 400000 && v4_fabric_step(&f) != 0; i++) { }
|
||||
CHECK(given_cells == f18_count && pool[0].n.reading && pool[0].n.read_port == V4_PORT_ANY && !pool[0].n.stopped,
|
||||
"it takes in the nucleus through its port and waits for a message: %u of %u cells", given_cells, f18_count);
|
||||
CHECK(given_cells == f18_count && pool[0].n.doing && pool[0].n.do_op == 8 && !pool[0].n.stopped,
|
||||
"it takes in the nucleus through its port, a word at a time, and sleeps until a message comes: %u of %u cells", given_cells, f18_count);
|
||||
|
||||
CHECK(told(0, "10 (ME) ! 1 (CONSOLE) ! 1 1 ROUTE") && ended_from == 10, "it is told it is 10, and where the console is");
|
||||
{
|
||||
@@ -501,64 +517,78 @@ int main(void)
|
||||
CHECK(strcmp(tell(10, "(LOST) @ ."), "0 ") == 0 && strcmp(tell(12, "(LOST) @ ."), "0 ") == 0, "and no message was let go");
|
||||
CHECK(waiting(10) && waiting(11) && waiting(12) && waiting(13) && waiting(14), "all five are waiting at their ports again");
|
||||
|
||||
/* ---- Hera kills a node by number, and tells the others it is gone (MESH.md 7b) ---- */
|
||||
|
||||
/* a node is killed while its neighbour is writing to it */
|
||||
step_limit = 3000000ul;
|
||||
CHECK(strcmp(tell(14, ": SPIN BEGIN 0 UNTIL ; SPIN"), "(still running)") == 0, "node 14 is stuck in a loop that never ends");
|
||||
CHECK(strcmp(tell(12, ": TO14 S\" 65 EMIT\" 14 SEND ; TO14"), "(still running)") == 0 && node_numbered(12)->asking,
|
||||
"node 12, beside it, sends it text: 14 never reads, and 12 is blocked writing to it");
|
||||
/* ---- Hera kills a node by number, and tells the others it is gone (MESH.md 7b, 7d) ----
|
||||
* A node that is stuck holds up no one: what is sent to it waits on its wire until the wire is full, and
|
||||
* is refused from then on; Hera can be typed to whatever any other node is doing, and her KILL of one
|
||||
* stuck node is not held by another (acceptance 3 and 4). */
|
||||
step_limit = 60000000ul;
|
||||
spinning = 1u << 13 | 1u << 14;
|
||||
(void)tell(14, ": SPIN BEGIN 0 UNTIL ; SPIN");
|
||||
(void)tell(13, ": SPIN BEGIN 0 UNTIL ; SPIN");
|
||||
CHECK(!waiting(14) && !waiting(13) && ended == 0, "nodes 13 and 14 are each stuck in a loop that never ends");
|
||||
CHECK(tell(12, ": TO14 S\" 65 EMIT\" 14 SEND ; TO14")[0] == 0 && ended == 1 && ended_how == V4_TEXT_COMPLETED && waiting(12) && going_from(12, 3) == 9,
|
||||
"node 12, beside 14, sends it text: the text waits on the wire, 14 never taking it, and node 12's line ends: \"%s\", %u cells", printed, going_from(12, 3));
|
||||
{
|
||||
v4_cell refused = node_numbered(12)->mem[REFUSED];
|
||||
CHECK(strstr(tell(12, ": FILL14 200 0 DO S\" 65 EMIT\" 14 SEND LOOP ; FILL14"), "Message refused") != NULL && ended == 1 && ended_how == V4_TEXT_ERROR
|
||||
&& node_numbered(12)->mem[REFUSED] == refused + 1 && going_from(12, 3) > V4_WIRE_CELLS - 9u,
|
||||
"it sends more: when the wire is full the next is refused at once, and told: \"%s\", %u cells on the wire", printed, going_from(12, 3));
|
||||
CHECK(strcmp(tell(12, "12 100 * ."), "1200 ") == 0 && waiting(12) && strcmp(tell(11, "11 100 * ."), "1100 ") == 0, "node 12 is not held, and goes on doing what it is sent; so does node 11");
|
||||
}
|
||||
CHECK(strcmp(tell(10, "1 2 + ."), "3 ") == 0, "Hera is typed to, with two nodes stuck");
|
||||
{
|
||||
unsigned born = born_count;
|
||||
const char *r = tell(10, "14 KILL 65 EMIT");
|
||||
CHECK(strstr(printed, "A") != NULL && node_numbered(14) == NULL && born_count == born, "Hera kills node 14, by its number: \"%s\"", r);
|
||||
CHECK(strcmp(r, "A") == 0 && ended == 1 && ended_how == V4_TEXT_COMPLETED && node_numbered(14) == NULL && born_count == born,
|
||||
"Hera kills node 14, by its number, with node 13 still stuck: the KILL ends, and the rest of her line is done: \"%s\"", r);
|
||||
CHECK(going_from(10, 4) == 8 && node_numbered(13) != NULL && !waiting(13), "her word to node 13 that 14 is gone waits on the wire to it: it is stuck, and she did not wait for it: %u cells", going_from(10, 4));
|
||||
}
|
||||
CHECK(!node_numbered(12)->asking && !node_numbered(12)->stopped && waiting(12), "node 12 is no longer blocked: it is waiting at its ports");
|
||||
CHECK(strstr(printed, "No one on that port") != NULL, "what it was doing ended in an error, which said so: \"%s\"", printed);
|
||||
step_limit = 30000000ul;
|
||||
CHECK(strcmp(tell(12, "12 100 * ."), "1200 ") == 0 && strcmp(tell(13, "13 100 * ."), "1300 ") == 0 && strcmp(tell(10, "1 2 + ."), "3 ") == 0, "and everything else keeps running: \"%s\"", printed);
|
||||
spinning = 1u << 13;
|
||||
CHECK(waiting(12) && waiting(11) && waiting(10), "every node that is not stuck is asleep again");
|
||||
CHECK(strcmp(tell(12, "12 100 * ."), "1200 ") == 0 && strcmp(tell(11, "11 100 * ."), "1100 ") == 0 && strcmp(tell(10, "1 2 + ."), "3 ") == 0, "and everything else keeps running: \"%s\"", printed);
|
||||
CHECK(strstr(tell(12, "5 3 PORT!"), "No one on that port") != NULL && waiting(12), "a write to the port node 14 was on is an error at once, not a wait: \"%s\"", printed);
|
||||
{
|
||||
v4_cell refused = node_numbered(12)->mem[REFUSED];
|
||||
v4_cell refused = node_numbered(12)->mem[REFUSED], r11 = node_numbered(11)->mem[REFUSED];
|
||||
CHECK(tell(12, ": AGAIN14 S\" 65 EMIT\" 14 SEND ; AGAIN14")[0] == 0 && node_numbered(12)->mem[REFUSED] == refused + 1 && waiting(12),
|
||||
"every node was told 14 is gone and forgot the way: what node 12 sends it now goes toward Hera, who has no way either, and is refused: \"%s\"", printed);
|
||||
"node 12 was told 14 is gone and forgot the way: what it sends it now goes toward Hera, who has no way either, and is refused: \"%s\"", printed);
|
||||
CHECK(tell(11, ": AGAIN14 S\" 65 EMIT\" 14 SEND ; AGAIN14")[0] == 0 && node_numbered(11)->mem[REFUSED] == r11 + 1 && waiting(11), "and so was node 11");
|
||||
CHECK(strstr(tell(10, ": H14 S\" 1\" 14 SEND ; H14"), "Argument out of range") != NULL, "Hera herself has no way to it");
|
||||
}
|
||||
|
||||
/* a node waits on one that is stuck and is not its neighbour; Hera kills the stuck one */
|
||||
step_limit = 3000000ul;
|
||||
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");
|
||||
(void)tell(12, ": W13 13 AWAIT . ; W13");
|
||||
CHECK(ended == 0 && node_numbered(12)->mem[AWAIT_FROM] == 13 && waiting(12), "node 12, which is not wired to node 13, waits for its answer, asleep");
|
||||
(void)tell(10, "13 KILL");
|
||||
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;
|
||||
spinning = 0;
|
||||
CHECK(strcmp(tell(12, "12 100 * ."), "1200 ") == 0 && strcmp(tell(11, "11 100 * ."), "1100 ") == 0, "and the others go on");
|
||||
|
||||
/* Hera's own wait, on a node that is stuck: a line from the console ends it */
|
||||
step_limit = 3000000ul;
|
||||
CHECK(strcmp(tell(12, ": SPIN BEGIN 0 UNTIL ; SPIN"), "(still running)") == 0, "node 12 is stuck in a loop");
|
||||
CHECK(strcmp(tell(10, "12 AWAIT ."), "(still running)") == 0 && node_numbered(10)->mem[AWAIT_FROM] == 12 && waiting(10), "Hera waits for its answer, which will not come");
|
||||
spinning = 1u << 12;
|
||||
(void)tell(12, ": SPIN BEGIN 0 UNTIL ; SPIN");
|
||||
(void)tell(10, "12 AWAIT .");
|
||||
CHECK(ended == 0 && !waiting(12) && node_numbered(10)->mem[AWAIT_FROM] == 12 && waiting(10), "node 12 is stuck in a loop; Hera waits for its answer, which will not come");
|
||||
{
|
||||
const char *r = tell(10, "12 KILL 66 EMIT");
|
||||
CHECK(strstr(r, "Interrupted\n") != NULL && strstr(r, "B") != NULL && strstr(r, "Interrupted\n") < strstr(r, "B") && ended == 2,
|
||||
"a line typed at the console ends her wait, with an error that says so, and is then done: \"%s\"", r);
|
||||
CHECK(node_numbered(12) == NULL && node_numbered(10)->mem[AWAIT_FROM] == 0, "the line killed the stuck node");
|
||||
}
|
||||
step_limit = 30000000ul;
|
||||
spinning = 0;
|
||||
|
||||
/* Hera blocked writing to a node that is stuck: a line from the console lets her go (MESH.md 7b.7) */
|
||||
step_limit = 3000000ul;
|
||||
CHECK(strcmp(tell(11, ": SPIN BEGIN 0 UNTIL ; SPIN"), "(still running)") == 0, "node 11 is stuck in a loop");
|
||||
CHECK(strcmp(tell(10, ": T11 S\" 1 DROP\" 11 SEND 67 EMIT ; T11"), "(still running)") == 0 && node_numbered(10)->asking,
|
||||
"Hera sends it text: its number is the higher, so she writes without looking, and is blocked");
|
||||
/* Hera sends to a node that is stuck: her line ends, and when the wire is full she is refused; she is never held */
|
||||
spinning = 1u << 11;
|
||||
(void)tell(11, ": SPIN BEGIN 0 UNTIL ; SPIN");
|
||||
CHECK(strcmp(tell(10, ": T11 S\" 1 DROP\" 11 SEND 67 EMIT ; T11"), "C") == 0 && ended == 1 && !waiting(11) && waiting(10),
|
||||
"node 11 is stuck in a loop; Hera sends it text, which waits on the wire, and the rest of her line is done: \"%s\"", printed);
|
||||
CHECK(strstr(tell(10, ": F11 200 0 DO S\" 1 DROP\" 11 SEND LOOP 67 EMIT ; F11"), "Message refused") != NULL && strstr(printed, "C") == NULL && ended_how == V4_TEXT_ERROR && waiting(10),
|
||||
"she sends more than the wire holds: the one there is no room for is refused at once, and her line ends there: \"%s\"", printed);
|
||||
{
|
||||
const char *r = tell(10, "11 KILL 68 EMIT");
|
||||
CHECK(strstr(r, "Interrupted\n") != NULL && strstr(r, "D") != NULL && strstr(r, "C") == NULL && strstr(r, "Interrupted\n") < strstr(r, "D"),
|
||||
"a line typed at the console ends the line that was blocked, with an error that says so, and is then done: \"%s\"", r);
|
||||
CHECK(node_numbered(11) == NULL && !node_numbered(10)->asking && waiting(10), "the line killed the stuck node, and Hera is back at her ports");
|
||||
CHECK(strcmp(r, "D") == 0 && node_numbered(11) == NULL && waiting(10), "she is typed to, and kills the stuck node: \"%s\"", r);
|
||||
}
|
||||
spinning = 0;
|
||||
CHECK(strcmp(tell(10, "1 2 + ."), "3 ") == 0, "and she goes on");
|
||||
step_limit = 30000000ul;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user