- 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>
94 lines
4.6 KiB
C
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 */
|