skip to content
==> 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}