Files
LithosAnanake/v4/include/v4/wire.h
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

94 lines
4.6 KiB
C

/* wire.h -- a queue of whole messages, one way along a wire.
* docs/v4.0.0/MESH.md section 7d.2.
*
* A message is what section 6 says: seven words, of which the seventh
* (word 6) is how many characters of text follow, 0 to 1024, and then the
* text, four characters to a word. On a queue it takes 7 cells and one for
* each word of text, and the queue holds V4_WIRE_CELLS of them, going round.
*
* ALL OF A MESSAGE OR NONE. Every function here leaves the queue exactly as
* it found it unless it answers V4_WIRE_DONE. There is no state in which
* part of a message has been put on, or taken off.
*
* THE MARK. The one that reads a queue has a mark on it: the message that
* look, take, move and drop are about. `mark` counts the cells from the
* front to where that message begins; equal to `used`, it is at no message,
* and those four answer V4_WIRE_NO_MESSAGE. A message put on the back of a
* queue whose mark is at no message is the one the mark is then at.
*
* THE LOOK. Whoever reads a queue looks at a message, decides, and then
* takes it, moves it or drops it; and the queue may have been emptied and
* filled again in between -- its wire cut and made again. So the queue
* keeps whether the message its mark is at is the one last looked at:
* `looked` is set by a look that finds a message, and cleared whenever the
* mark is moved, the marked message goes, or the queue is reset. A node's
* take, move and drop are done only while it is set (fabric.c): they are
* then about the very message that was looked at, of the length the look
* gave, and no other.
*
* Nothing here allocates, and nothing uses the C library: whoever owns the
* queue supplies its memory.
*/
#ifndef V4_WIRE_H
#define V4_WIRE_H
#include "v4/cell.h"
#ifndef V4_WIRE_CELLS
#define V4_WIRE_CELLS 1024
#endif
#define V4_WIRE_HEADER 7u /* the words of a message that are not its text */
/* a wire must be able to hold the largest message there is: 1,024 characters */
typedef char v4_wire_holds_a_message[(V4_WIRE_CELLS >= 7 + 1024 / 4) ? 1 : -1];
typedef struct {
v4_cell cell[V4_WIRE_CELLS]; /* the messages, one after another, going round */
unsigned head; /* where the front message begins */
unsigned used; /* how many cells they take */
unsigned mark; /* how many cells from the front the reader's mark is; == used: at no message */
unsigned arrived; /* not 0: a message has come since the reader last asked which wires have one */
unsigned freed; /* not 0: a message has come off since the writer was last woken from a sleep for room */
unsigned looked; /* not 0: the message the mark is at is the one last looked at: see THE LOOK */
} v4_wire_queue;
enum { V4_WIRE_DONE = 0, V4_WIRE_NO_ROOM = 1, V4_WIRE_NO_ONE = 2, V4_WIRE_NO_MESSAGE = 3, V4_WIRE_NOT_A_MESSAGE = 4 };
/* Empty, and the mark at no message. */
void v4_wire_reset(v4_wire_queue *q);
/* The cells a message of `length` characters takes: 7 and a cell for each
* four characters. 0 if `length` is not 0 to 1024: it is not a message. */
unsigned v4_wire_cells(v4_cell length);
/* V4_WIRE_DONE if `cells` more would fit, V4_WIRE_NO_ROOM if not. Changes
* nothing. */
int v4_wire_room(const v4_wire_queue *q, unsigned cells);
/* The message whose seven words are at `header7` and whose text, a cell to
* four characters, is at `text` goes on the back. V4_WIRE_NOT_A_MESSAGE if
* word 6 is not 0 to 1024, V4_WIRE_NO_ROOM if it does not fit. */
int v4_wire_put(v4_wire_queue *q, const v4_cell *header7, const v4_cell *text);
/* The mark to the front message; to the one after the marked one, or
* V4_WIRE_NO_MESSAGE if there is none (the mark is then at no message). */
void v4_wire_first(v4_wire_queue *q);
int v4_wire_next(v4_wire_queue *q);
/* The marked message: its seven words copied out and nothing taken;
* copied out and taken off the queue, its text to `text`, which holds
* `text_cap` cells (V4_WIRE_NOT_A_MESSAGE if that is too few); taken off and
* gone. After a take or a drop the mark is at the message that followed.
* V4_WIRE_NO_MESSAGE with the mark at no message. */
int v4_wire_look(v4_wire_queue *q, v4_cell *header7);
int v4_wire_take(v4_wire_queue *q, v4_cell *header7, v4_cell *text, unsigned text_cap);
int v4_wire_drop(v4_wire_queue *q);
/* The marked message of `from` goes to the back of `to`, with its fourth
* word (word 3) one fewer: how many more nodes may pass it on. V4_WIRE_NO_ROOM
* if `to` has no room for it, or is `from`. */
int v4_wire_move(v4_wire_queue *from, v4_wire_queue *to);
#endif /* V4_WIRE_H */