Files
LithosAnanake/v4/src/wire.c
T
rajamesandClaude Opus 5.5 f1419e739c fix(v4.0.0): step 6e review round 2 -- only the message looked at is taken, moved or dropped; the kernel's port has no queue in a fabric; an answer nobody awaits is not a loss
- Engine: a wire keeps whether the message at its mark is the one last
  looked at; a node's take, move and drop of any other answer 3 and write
  nothing (MESH.md 7d.3).  A wire cut and made again between a look and a
  take no longer has a NACK done as text, or 256 cells written where one
  was looked for.
- Engine: v4_fabric_wire_kernel wires a kernel to a port with no queues;
  a message for it is refused at once, error 18, on a mesh as on the
  products.
- The result of a drop is looked at; a take that does not take has the
  message dropped, or gone past: nothing goes round.
- An answer nobody waits for is let go uncounted; (LOST) counts what should
  have been delivered or acted on and was not.  The flood's account is
  exact.
- Error 18 from under a word that was printing empties the data stack, as
  a fault does: that word's own values are not left there.
- Tests: the take and drop windows cut at every step, with and without
  another message put; a refusal owed to a stuck node whose wire is full.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 22:36:59 -04:00

132 lines
3.8 KiB
C

/* wire.c -- a queue of whole messages. See wire.h.
*
* Nothing here uses the C library: the bare-metal kernel links this file.
*/
#include "v4/wire.h"
#include "v4/message.h"
void v4_wire_reset(v4_wire_queue *q)
{
unsigned i;
for (i = 0; i < V4_WIRE_CELLS; i++) q->cell[i] = 0;
q->head = 0;
q->used = 0;
q->mark = 0;
q->arrived = 0;
q->freed = 0;
q->looked = 0;
}
unsigned v4_wire_cells(v4_cell length)
{
if (length < 0 || length > (v4_cell)V4_MSG_MAX_CHARS) return 0;
return V4_WIRE_HEADER + ((unsigned)length + 3u) / 4u;
}
/* the cell `off` cells from the front */
static unsigned slot(const v4_wire_queue *q, unsigned off)
{
unsigned s = q->head + off;
return s >= V4_WIRE_CELLS ? s - V4_WIRE_CELLS : s;
}
/* the cells the message `off` cells from the front takes */
static unsigned size_at(const v4_wire_queue *q, unsigned off)
{
return v4_wire_cells(q->cell[slot(q, off + 6u)]);
}
int v4_wire_room(const v4_wire_queue *q, unsigned cells)
{
return cells <= V4_WIRE_CELLS - q->used ? V4_WIRE_DONE : V4_WIRE_NO_ROOM;
}
/* `n` cells, already checked to fit, onto the back */
static unsigned back(v4_wire_queue *q, unsigned n)
{
unsigned at = q->used;
q->used += n;
q->arrived = 1;
return at;
}
int v4_wire_put(v4_wire_queue *q, const v4_cell *header7, const v4_cell *text)
{
unsigned n = v4_wire_cells(header7[6]), at, i;
if (n == 0) return V4_WIRE_NOT_A_MESSAGE;
if (v4_wire_room(q, n) != V4_WIRE_DONE) return V4_WIRE_NO_ROOM;
at = back(q, n);
for (i = 0; i < V4_WIRE_HEADER; i++) q->cell[slot(q, at + i)] = header7[i];
for (; i < n; i++) q->cell[slot(q, at + i)] = text[i - V4_WIRE_HEADER];
return V4_WIRE_DONE;
}
void v4_wire_first(v4_wire_queue *q)
{
q->looked = 0;
q->mark = 0;
}
int v4_wire_next(v4_wire_queue *q)
{
q->looked = 0;
if (q->mark >= q->used) return V4_WIRE_NO_MESSAGE;
q->mark += size_at(q, q->mark);
return q->mark < q->used ? V4_WIRE_DONE : V4_WIRE_NO_MESSAGE;
}
int v4_wire_look(v4_wire_queue *q, v4_cell *header7)
{
unsigned i;
if (q->mark >= q->used) return V4_WIRE_NO_MESSAGE;
for (i = 0; i < V4_WIRE_HEADER; i++) header7[i] = q->cell[slot(q, q->mark + i)];
q->looked = 1;
return V4_WIRE_DONE;
}
/* the marked message is off the queue; the mark is at the one that followed */
static void remove_marked(v4_wire_queue *q)
{
unsigned n = size_at(q, q->mark), i;
if (q->mark == 0) {
q->head = slot(q, n);
} else {
for (i = q->mark; i + n < q->used; i++) q->cell[slot(q, i)] = q->cell[slot(q, i + n)];
}
q->used -= n;
q->freed = 1;
q->looked = 0;
}
int v4_wire_take(v4_wire_queue *q, v4_cell *header7, v4_cell *text, unsigned text_cap)
{
unsigned n, i;
if (q->mark >= q->used) return V4_WIRE_NO_MESSAGE;
n = size_at(q, q->mark);
if (n - V4_WIRE_HEADER > text_cap) return V4_WIRE_NOT_A_MESSAGE;
for (i = 0; i < V4_WIRE_HEADER; i++) header7[i] = q->cell[slot(q, q->mark + i)];
for (; i < n; i++) text[i - V4_WIRE_HEADER] = q->cell[slot(q, q->mark + i)];
remove_marked(q);
return V4_WIRE_DONE;
}
int v4_wire_drop(v4_wire_queue *q)
{
if (q->mark >= q->used) return V4_WIRE_NO_MESSAGE;
remove_marked(q);
return V4_WIRE_DONE;
}
int v4_wire_move(v4_wire_queue *from, v4_wire_queue *to)
{
unsigned n, at, i;
if (from->mark >= from->used) return V4_WIRE_NO_MESSAGE;
n = size_at(from, from->mark);
if (from == to || v4_wire_room(to, n) != V4_WIRE_DONE) return V4_WIRE_NO_ROOM;
at = back(to, n);
for (i = 0; i < n; i++) to->cell[slot(to, at + i)] = from->cell[slot(from, from->mark + i)];
to->cell[slot(to, at + 3u)] = (v4_cell)((v4_ucell)from->cell[slot(from, from->mark + 3u)] - 1u); /* in the unsigned type: no overflow at the least cell */
remove_marked(from);
return V4_WIRE_DONE;
}