==> tests/pipe.c <==1/* The table-level tests of alpha-rust-mesh's mesh-abi pipe.rs, ported one for
2 * one: host_push_pop_through_the_tables and hold_and_flight. */
3#include "mesh/abi/pipe.h"
4#include "mesh/abi/view_heap.h"
5#include "mesh/check.h"
6#include "mem.h"
7
8static uint32_t le32(const uint8_t *b) { return (uint32_t)b[0] | (uint32_t)b[1] << 8 | (uint32_t)b[2] << 16 | (uint32_t)b[3] << 24; }
9
10static void host_push_pop_through_the_tables(void) {
11 /* Consumer slot 2 (inbox at view + 0x80, 8 x 8 bytes: two sides of 4), producer slot 5 feeding it. */
12 mem *m = mem_new(MESH_MAILBOX_BYTES);
13 const mesh_words *w = &m->words;
14 uint8_t ones[8], r4[4];
15 memset(ones, 1, 8);
16 memset(r4, 1, 4);
17 mem_set(m, mesh_prog_entry(2) + MESH_PT_STATE, MESH_ST_RUNNING);
18 mem_set(m, mesh_prog_entry(2) + MESH_PT_VIEW_OFF, MESH_VIEW_HEAP);
19 mem_set(m, mesh_pipe_entry(2) + MESH_PP_IN_OFF, 0x80);
20 mem_set(m, mesh_pipe_entry(2) + MESH_PP_IN_CAP, 8);
21 mem_set(m, mesh_pipe_entry(2) + MESH_PP_IN_REC, 8);
22 mem_set(m, mesh_prog_entry(5) + MESH_PT_STATE, MESH_ST_RUNNING);
23 CHECK_I(mesh_pipe_push(w, 5, 2, ones, 8), -MESH_PIPE_ERR_NOT_CONNECTED);
24 mem_set(m, mesh_pipe_entry(5) + MESH_PP_FEEDS_MASK, 1u << 2);
25 CHECK_I(mesh_pipe_push(w, 5, 2, r4, 4), -MESH_PIPE_ERR_SIZE);
26 /* Host code pushes on the CPU side: 4 records fill it. */
27 for (uint8_t i = 0; i < 4; i++) {
28 uint8_t rec[8];
29 memset(rec, i, 8);
30 CHECK_I(mesh_pipe_push(w, 5, 2, rec, 8), 1);
31 }
32 uint8_t nine[8];
33 memset(nine, 9, 8);
34 CHECK_I(mesh_pipe_push(w, 5, 2, nine, 8), 0);
35 mesh_pipe_inbox inbox;
36 CHECK_I(mesh_pipe_target(w, 2, 2, &inbox), 0);
37 mesh_pipe_ring cpu = mesh_pipe_inbox_side(&inbox, MESH_PIPE_SIDE_CPU), gpu = mesh_pipe_inbox_side(&inbox, MESH_PIPE_SIDE_GPU);
38 CHECK_U(cpu.base, MESH_VIEW_HEAP + 0x80);
39 CHECK_U(mem_get(m, cpu.base + MESH_PIPE_PI_FULL), 1);
40 CHECK_U(mesh_pipe_ring_len(&cpu, w), 4);
41 CHECK_U(mesh_pipe_ring_len(&gpu, w), 0);
42 /* A GPU producer's records go to the other side (its head is never CASed by the host's pushes). */
43 for (uint32_t i = 0; i < 2; i++) {
44 uint32_t p;
45 CHECK(mesh_pipe_ring_reserve_push(&gpu, w, 6, &p));
46 uint32_t v[2] = {0x100 + i, 0x100 + i};
47 mem_put(m, &gpu, p, v, 2);
48 mesh_pipe_ring_commit_push(&gpu, w, p);
49 }
50 CHECK_U(mesh_pipe_inbox_len(&inbox, w), 6);
51 /* The consumer drains both, the fuller side first; each side in order. */
52 uint8_t out[8];
53 uint32_t got[8], n = 0;
54 while (n < 8 && mesh_pipe_pop(w, 2, out, 8) == 1) got[n++] = le32(out);
55 CHECK_U(n, 6);
56 uint32_t c[4], g[2], nc = 0, ng = 0;
57 for (uint32_t i = 0; i < n; i++) {
58 if (got[i] == 0x100 || got[i] == 0x101) g[ng < 2 ? ng++ : ng] = got[i];
59 else if (nc < 4) c[nc++] = got[i];
60 }
61 CHECK_U(nc, 4);
62 CHECK_U(ng, 2);
63 CHECK_U(c[0], 0);
64 CHECK_U(c[1], 0x01010101u);
65 CHECK_U(c[2], 0x02020202u);
66 CHECK_U(c[3], 0x03030303u);
67 CHECK_U(g[0], 0x100);
68 CHECK_U(g[1], 0x101);
69 CHECK_U(got[0], 0); /* the CPU side was fuller */
70 CHECK_I(mesh_pipe_pop(w, 2, out, 8), 0);
71 CHECK_I(mesh_pipe_pop(w, 5, out, 8), -MESH_PIPE_ERR_NOT_CONNECTED);
72 mem_set(m, mesh_prog_entry(2) + MESH_PT_STATE, MESH_ST_EMPTY);
73 CHECK_I(mesh_pipe_push(w, 5, 2, ones, 8), -MESH_PIPE_ERR_GONE);
74 /* Unloaded, then the feed disconnected: still Gone (a stale slot id is no fault). */
75 mem_set(m, mesh_pipe_entry(5) + MESH_PP_FEEDS_MASK, 0);
76 CHECK_I(mesh_pipe_push(w, 5, 2, ones, 8), -MESH_PIPE_ERR_GONE);
77 mem_free(m);
78}
79
80static void hold_and_flight(void) {
81 mem *m = mem_new(MESH_MAILBOX_BYTES);
82 const mesh_words *w = &m->words;
83 uint8_t ones[8], r4[4], out[8];
84 memset(ones, 1, 8);
85 memset(r4, 1, 4);
86 mem_set(m, mesh_prog_entry(2) + MESH_PT_STATE, MESH_ST_RUNNING);
87 mem_set(m, mesh_prog_entry(2) + MESH_PT_VIEW_OFF, MESH_VIEW_HEAP);
88 mem_set(m, mesh_pipe_entry(2) + MESH_PP_IN_OFF, 0x80);
89 mem_set(m, mesh_pipe_entry(2) + MESH_PP_IN_CAP, 4);
90 mem_set(m, mesh_pipe_entry(2) + MESH_PP_IN_REC, 8);
91 mem_set(m, mesh_prog_entry(5) + MESH_PT_STATE, MESH_ST_RUNNING);
92 mem_set(m, mesh_pipe_entry(5) + MESH_PP_FEEDS_MASK, 1u << 2);
93 mem_set(m, mesh_pipe_entry(2) + MESH_PP_IN_HOLD, 1);
94 CHECK_I(mesh_pipe_push(w, 5, 2, ones, 8), 0); /* held: full, not a fault */
95 mesh_pipe_inbox in;
96 int t = mesh_pipe_target(w, 5, 2, &in);
97 CHECK_I(mesh_pipe_code(t < 0 ? t : 1), MESH_PIPE_NONE);
98 mem_set(m, mesh_pipe_entry(2) + MESH_PP_IN_HOLD, 0);
99 CHECK_I(mesh_pipe_push(w, 5, 2, ones, 8), 1);
100 CHECK_U(mem_get(m, mesh_pipe_entry(5) + MESH_PP_FLIGHT), 0); /* every push ends its flight */
101 CHECK_I(mesh_pipe_push(w, 5, 2, r4, 4), -MESH_PIPE_ERR_SIZE);
102 CHECK_U(mem_get(m, mesh_pipe_entry(5) + MESH_PP_FLIGHT), 0);
103 /* The epoch's parity picks the word: an odd epoch counts in PP_FLIGHT1. */
104 mem_set(m, MESH_H_PIPE_EPOCH, 3);
105 uint32_t parity = mesh_pipe_flight_begin(w, 5);
106 CHECK_U(parity, 1);
107 CHECK_U(mem_get(m, mesh_flight_word(5, 1)), 1);
108 CHECK_U(mem_get(m, mesh_flight_word(5, 0)), 0);
109 mem_set(m, MESH_H_PIPE_EPOCH, 4); /* meshd moved on: the push still ends in the word it counted in */
110 mesh_pipe_flight_end(w, 5, parity);
111 CHECK_U(mem_get(m, mesh_flight_word(5, 1)), 0);
112 /* A block that keeps changing: busy, bounded. */
113 mem_set(m, mesh_prog_entry(2) + MESH_PT_GEN, 1);
114 CHECK_I(mesh_pipe_push(w, 5, 2, ones, 8), 0);
115 CHECK_I(mesh_pipe_pop(w, 2, out, 8), 0);
116 mem_free(m);
117}
118
119/* code() over every result, as the runtimes return them. */
120static void codes(void) {
121 CHECK_I(mesh_pipe_code(1), MESH_PIPE_OK);
122 CHECK_I(mesh_pipe_code(0), MESH_PIPE_NONE);
123 CHECK_I(mesh_pipe_code(-MESH_PIPE_ERR_NOT_CONNECTED), MESH_PIPE_NOT_CONNECTED);
124 CHECK_I(mesh_pipe_code(-MESH_PIPE_ERR_SIZE), MESH_PIPE_SIZE);
125 CHECK_I(mesh_pipe_code(-MESH_PIPE_ERR_GONE), MESH_PIPE_GONE);
126 CHECK_I(mesh_pipe_code(-MESH_PIPE_ERR_BUSY), MESH_PIPE_NONE);
127 CHECK_I(-MESH_PIPE_ERR_NOT_CONNECTED, MESH_PIPE_NOT_CONNECTED);
128 CHECK_I(-MESH_PIPE_ERR_SIZE, MESH_PIPE_SIZE);
129 CHECK_I(-MESH_PIPE_ERR_GONE, MESH_PIPE_GONE);
130}
131
132int main(void) {
133 host_push_pop_through_the_tables();
134 hold_and_flight();
135 codes();
136 return mesh_check_done();
137}