/* 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; }