==> tests/node.c <==1/* mesh-worker lib.rs's tests, one for one: the node loop runs a ring like
2 * mesh-rt; faults, requests and peer views; the input queue pops once each. */
3#include "mesh/check.h"
4#include "mesh/worker_node.h"
5
6#include "mesh/abi/control_block.h"
7#include "mesh/abi/fault.h"
8#include "mesh/abi/input_queue.h"
9#include "mesh/abi/node.h"
10#include "mesh/abi/ops.h"
11#include "mesh/abi/program_table.h"
12#include "mesh/abi/ring.h"
13#include "mesh/abi/trace.h"
14
15#include <pthread.h>
16#include <sched.h>
17#include <stdlib.h>
18#include <string.h>
19#include <time.h>
20
21/* The table entry meshd would write for a slot (view, nodes, request window). */
22static void install(mesh_mailbox mb, uint32_t s, uint32_t nodes, uint32_t view_off, uint32_t view_bytes) {
23 size_t e = mesh_prog_entry(s);
24 const uint32_t kv[][2] = {{MESH_PT_VIEW_OFF, view_off}, {MESH_PT_VIEW_BYTES, view_bytes}, {MESH_PT_NODES, nodes}, {MESH_PT_STATE, MESH_ST_RUNNING},
25 {MESH_PT_REQ_OFF, 0x100}, {MESH_PT_REQ_MAX, 0x40}, {MESH_PT_RESP_OFF, 0x200}, {MESH_PT_RESP_MAX, 0x40}};
26 for (size_t i = 0; i < 8; i++) mesh_mailbox_set(mb, e + kv[i][0], kv[i][1]);
27 mesh_mailbox_set(mb, e + MESH_PT_NAME, 't' | 's' << 8 | 't' << 16);
28}
29
30static void publish(mesh_mailbox mb, uint32_t s, uint32_t t, uint32_t op, uint32_t arg) {
31 size_t e = mesh_prog_ctl(s) + MESH_P_RING + MESH_ENTRY_BYTES * (t % MESH_PROG_RING);
32 mesh_mailbox_set(mb, e + MESH_E_OP, op);
33 mesh_mailbox_set(mb, e + MESH_E_ARG, arg);
34 mesh_mailbox_set(mb, e + MESH_E_SLOT, t % MESH_PROG_RESULTS);
35 mesh_mailbox_publish(mb, e + MESH_E_SEQ, t + 1);
36}
37
38static bool done(mesh_mailbox mb, uint32_t s, uint32_t t, uint32_t *result) {
39 size_t c = mesh_prog_ctl(s), k = t % MESH_PROG_RESULTS;
40 if (mesh_mailbox_get(mb, c + MESH_P_MARKS + 4 * k) != t + 1) return false;
41 if (result) *result = mesh_mailbox_get(mb, c + MESH_P_RESULTS + 4 * k);
42 return true;
43}
44
45static void init(const mesh_worker_ctx *c, void *u) {
46 (void)u;
47 mesh_ctx_set_u32(c, 0, 0x4f4c4548);
48}
49static uint32_t task(const mesh_worker_ctx *c, uint32_t op, uint32_t arg, void *u) {
50 (void)u;
51 if (op != MESH_OP_TASK) return MESH_R_BAD_OP;
52 mesh_ctx_count(c, 0, 1);
53 mesh_view_add_u32(mesh_ctx_view(c), 8, 1);
54 return arg * 3 + 7;
55}
56
57typedef struct {
58 mesh_mailbox mb;
59 atomic_bool stop;
60} run_arg;
61
62static const mesh_worker_program prog = {init, task, NULL};
63static void *runner(void *a) {
64 run_arg *r = a;
65 mesh_worker_run_nodes(r->mb, 3, &prog, &r->stop);
66 return NULL;
67}
68
69static double secs(const struct timespec *t0) {
70 struct timespec t;
71 clock_gettime(CLOCK_MONOTONIC, &t);
72 return (double)(t.tv_sec - t0->tv_sec) + (double)(t.tv_nsec - t0->tv_nsec) / 1e9;
73}
74
75static void nodes_run_the_ring_like_mesh_rt(void) {
76 mesh_mailbox mb = mesh_mailbox_test();
77 install(mb, 3, 4, 0x100000, 0x1000);
78 run_arg r = {mb, false};
79 pthread_t th;
80 pthread_create(&th, NULL, runner, &r);
81 struct timespec t0;
82 clock_gettime(CLOCK_MONOTONIC, &t0);
83 while (mesh_mailbox_get(mb, mesh_prog_ctl(3) + MESH_P_ONLINE) < 4) {
84 if (!CHECK(secs(&t0) < 5)) break;
85 sched_yield();
86 }
87 publish(mb, 3, 0, MESH_OP_INIT, 0);
88 for (uint32_t t = 1; t < 200; t++) {
89 /* The publisher never runs PROG_RING ahead of the oldest outstanding ticket. */
90 while (t >= MESH_PROG_RING && !done(mb, 3, t - MESH_PROG_RING, NULL)) sched_yield();
91 publish(mb, 3, t, t == 150 ? 9 : MESH_OP_TASK, t);
92 }
93 clock_gettime(CLOCK_MONOTONIC, &t0);
94 while (mesh_mailbox_get(mb, mesh_prog_ctl(3) + MESH_P_DONE) < 200) {
95 if (!CHECK(secs(&t0) < 5)) break;
96 sched_yield();
97 }
98 mesh_mailbox_publish(mb, mesh_prog_ctl(3) + MESH_P_SHUTDOWN, MESH_SHUTDOWN_HALT);
99 pthread_join(th, NULL);
100 size_t c = mesh_prog_ctl(3);
101 CHECK_U(mesh_mailbox_get(mb, c + MESH_P_HALTED), 4);
102 CHECK_U(mesh_mailbox_get(mb, c + MESH_P_DONE), 200);
103 CHECK_U(mesh_mailbox_get(mb, c + MESH_P_COUNTERS), 198);
104 uint32_t res;
105 CHECK(done(mb, 3, 199, &res) && res == 199 * 3 + 7);
106 CHECK(done(mb, 3, 150, &res) && res == MESH_R_BAD_OP);
107 CHECK_U(mesh_mailbox_get(mb, 0x100000), 0x4f4c4548);
108 CHECK_U(mesh_mailbox_get(mb, 0x100008), 198);
109 uint32_t tasks = 0;
110 for (uint32_t n = 0; n < 4; n++) tasks += mesh_mailbox_get(mb, mesh_node_rec(3, n) + MESH_N_TASKS);
111 CHECK_U(tasks, 200);
112 CHECK_U(mesh_mailbox_get(mb, c + MESH_P_TRACE_N), 200);
113 CHECK_U(mesh_mailbox_get(mb, c + MESH_P_FAULT), 0);
114 /* The trace record of ticket 199: slot | node << 8 | op << 16, the ticket, start <= end. */
115 size_t tr = 0;
116 for (uint32_t n = 0; n < 200; n++)
117 if (mesh_mailbox_get(mb, mesh_trace_rec(3, n) + 4) == 199) tr = mesh_trace_rec(3, n);
118 CHECK(tr != 0);
119 CHECK_U(mesh_mailbox_get(mb, tr) & 0xff, 3);
120 CHECK(mesh_mailbox_get(mb, tr + 12) - mesh_mailbox_get(mb, tr + 8) < 1u << 31);
121 free(mb.base);
122}
123
124static void faults_requests_and_peers(void) {
125 mesh_mailbox mb = mesh_mailbox_test();
126 install(mb, 1, 1, 0x100000, 0x400);
127 install(mb, 2, 1, 0x101000, 0x40);
128 mesh_mailbox_set(mb, 0x101000, 77);
129 mesh_worker_ctx c;
130 mesh_worker_ctx_new(mb, 1, 0, &c);
131 /* Bounds: a read past the view is 0 and records the first fault. */
132 CHECK_U(mesh_ctx_view_u32(&c, 0x400), 0);
133 CHECK_U(mesh_mailbox_get(mb, mesh_prog_ctl(1) + MESH_P_FAULT), MESH_FAULT_VIEW_BOUNDS | 0x400 << 8);
134 mesh_ctx_set_u32(&c, 0x3fd, 1);
135 CHECK_U(mesh_mailbox_get(mb, mesh_prog_ctl(1) + MESH_P_FAULT), MESH_FAULT_VIEW_BOUNDS | 0x400 << 8);
136 mesh_mailbox_set(mb, mesh_prog_ctl(1) + MESH_P_FAULT, 0);
137 /* Peer views need the reads mask (re-read per call). */
138 mesh_view pv;
139 CHECK(!mesh_ctx_peer_view(&c, 2, &pv));
140 CHECK_U(mesh_mailbox_get(mb, mesh_prog_ctl(1) + MESH_P_FAULT) & 0xff, MESH_FAULT_PEER_VIEW);
141 mesh_mailbox_set(mb, mesh_prog_entry(1) + MESH_PT_READS_MASK, 1 << 2);
142 CHECK(mesh_ctx_peer_view(&c, 2, &pv) && mesh_view_u32(pv, 0) == 77);
143 uint32_t s = 99;
144 CHECK(mesh_ctx_find(&c, "tst", &s) && s == 1);
145 char name[17];
146 mesh_ctx_prog_name(&c, 2, name);
147 CHECK_S(name, "tst");
148 /* The request window: request bytes, the response and its sequence. */
149 mesh_mailbox_set(mb, mesh_prog_ctl(1) + MESH_P_REQ_LEN, 5);
150 mesh_view_write(mesh_ctx_view(&c), 0x100, (const uint8_t *)"hello", 5);
151 mesh_mailbox_publish64(mb, mesh_prog_ctl(1) + MESH_P_REQ_SEQ, 9);
152 uint8_t b[5];
153 CHECK(mesh_view_read(mesh_ctx_request(&c), 0, b, 5) && memcmp(b, "hello", 5) == 0);
154 mesh_view_write(mesh_ctx_response(&c), 0, (const uint8_t *)"olleh", 5);
155 mesh_ctx_respond(&c, 5);
156 CHECK_U(mesh_mailbox_get64(mb, mesh_prog_ctl(1) + MESH_P_RESP_SEQ), 9);
157 CHECK_U(mesh_mailbox_get(mb, mesh_prog_ctl(1) + MESH_P_RESP_LEN), 5);
158 /* Bulk f32s and their bounds. */
159 float f2[2] = {1.5f, -2.0f};
160 CHECK(mesh_view_write_f32s(mesh_ctx_view(&c), 0x20, f2, 2));
161 CHECK(mesh_ctx_view_f32(&c, 0x20) == 1.5f && mesh_ctx_view_f32(&c, 0x24) == -2.0f);
162 CHECK(!mesh_view_write_f32s(mesh_ctx_view(&c), 0x3fc, f2, 2));
163 free(mb.base);
164}
165
166typedef struct {
167 mesh_mailbox mb;
168 uint32_t node;
169 uint8_t got[16];
170 size_t n;
171} popper;
172
173static void *pop_all(void *a) {
174 popper *p = a;
175 mesh_worker_ctx c;
176 mesh_worker_ctx_new(p->mb, 0, p->node, &c);
177 uint8_t b;
178 while (mesh_ctx_input_pop(&c, &b)) p->got[p->n++] = b;
179 return NULL;
180}
181
182static void input_queue_pops_once_each(void) {
183 mesh_mailbox mb = mesh_mailbox_test();
184 install(mb, 0, 2, 0x100000, 0x1000);
185 uint32_t off = 0x800, len = 64;
186 mesh_mailbox_set(mb, mesh_prog_entry(0) + MESH_PT_INPUT_OFF, off);
187 mesh_mailbox_set(mb, mesh_prog_entry(0) + MESH_PT_INPUT_LEN, len);
188 size_t q = 0x100000 + off;
189 const char *bytes = "abcdefgh";
190 for (size_t i = 0; i < 8; i++) {
191 size_t at = q + MESH_IQ_DATA + i;
192 mesh_mailbox_set(mb, at & ~(size_t)3, mesh_mailbox_get(mb, at & ~(size_t)3) | (uint32_t)(uint8_t)bytes[i] << (8 * (at & 3)));
193 }
194 mesh_mailbox_publish(mb, q + MESH_IQ_HEAD, 8);
195 mesh_worker_ctx c;
196 mesh_worker_ctx_new(mb, 0, 0, &c);
197 CHECK_U(mesh_ctx_input_pending(&c), 8);
198 popper x = {mb, 0, {0}, 0}, y = {mb, 1, {0}, 0};
199 pthread_t tx, ty;
200 pthread_create(&tx, NULL, pop_all, &x);
201 pthread_create(&ty, NULL, pop_all, &y);
202 pthread_join(tx, NULL);
203 pthread_join(ty, NULL);
204 CHECK_U(x.n + y.n, 8);
205 int seen[256] = {0};
206 for (size_t i = 0; i < x.n; i++) seen[x.got[i]]++;
207 for (size_t i = 0; i < y.n; i++) seen[y.got[i]]++;
208 for (size_t i = 0; i < 8; i++) CHECK_I(seen[(uint8_t)bytes[i]], 1);
209 uint8_t b;
210 CHECK(!mesh_ctx_input_pop(&c, &b));
211 free(mb.base);
212}
213
214int main(void) {
215 nodes_run_the_ring_like_mesh_rt();
216 faults_requests_and_peers();
217 input_queue_pops_once_each();
218 return mesh_check_done();
219}