==> tests/mem.h <==1/* A word-addressed memory of C11 atomics behind mesh_words: the tests' mailbox,
2 * as Rust's tests use a Vec<AtomicU32>. */
3#ifndef MESH_TEST_MEM_H
4#define MESH_TEST_MEM_H
5
6#include "mesh/abi/words.h"
7
8#include <stdatomic.h>
9#include <stdlib.h>
10
11typedef struct {
12 _Atomic uint32_t *w;
13 size_t n;
14 mesh_words words;
15} mem;
16
17static uint32_t mem_load(void *c, size_t a) { return atomic_load_explicit(&((mem *)c)->w[a / 4], memory_order_acquire); }
18static void mem_store(void *c, size_t a, uint32_t v) { atomic_store_explicit(&((mem *)c)->w[a / 4], v, memory_order_release); }
19static uint32_t mem_cas(void *c, size_t a, uint32_t cmp, uint32_t desired) {
20 uint32_t seen = cmp;
21 atomic_compare_exchange_strong_explicit(&((mem *)c)->w[a / 4], &seen, desired, memory_order_acq_rel, memory_order_acquire);
22 return seen;
23}
24static uint32_t mem_add(void *c, size_t a, uint32_t v) { return atomic_fetch_add_explicit(&((mem *)c)->w[a / 4], v, memory_order_acq_rel); }
25static void mem_read(void *c, size_t a, uint8_t *out, size_t n) {
26 for (size_t i = 0; 4 * i < n; i++) {
27 uint32_t v = atomic_load_explicit(&((mem *)c)->w[a / 4 + i], memory_order_relaxed);
28 for (size_t k = 0; k < 4 && 4 * i + k < n; k++) out[4 * i + k] = (uint8_t)(v >> (8 * k));
29 }
30}
31static void mem_write(void *c, size_t a, const uint8_t *b, size_t n) {
32 for (size_t i = 0; 4 * i < n; i++) {
33 uint32_t v = 0;
34 for (size_t k = 0; k < 4 && 4 * i + k < n; k++) v |= (uint32_t)b[4 * i + k] << (8 * k);
35 atomic_store_explicit(&((mem *)c)->w[a / 4 + i], v, memory_order_relaxed);
36 }
37}
38
39static inline mem *mem_new(size_t bytes) {
40 mem *m = calloc(1, sizeof *m);
41 m->n = bytes / 4;
42 m->w = calloc(m->n, sizeof *m->w);
43 m->words = (mesh_words){m, mem_load, mem_store, mem_cas, mem_add, NULL, mem_read, mem_write};
44 return m;
45}
46static inline void mem_free(mem *m) {
47 free((void *)m->w);
48 free(m);
49}
50/* Plain (relaxed) word access for setting up and inspecting. */
51static inline void mem_set(mem *m, size_t a, uint32_t v) { atomic_store_explicit(&m->w[a / 4], v, memory_order_relaxed); }
52static inline uint32_t mem_get(mem *m, size_t a) { return atomic_load_explicit(&m->w[a / 4], memory_order_relaxed); }
53
54/* Writes position p's record (words v[0..n)) and its sum, as a producer would. */
55static inline void mem_put(mem *m, const mesh_pipe_ring *r, uint32_t p, const uint32_t *v, size_t n) {
56 uint8_t b[4096];
57 for (size_t i = 0; i < n; i++) {
58 mem_set(m, mesh_pipe_ring_cell(r, p) + 4 * i, v[i]);
59 for (int k = 0; k < 4; k++) b[4 * i + (size_t)k] = (uint8_t)(v[i] >> (8 * k));
60 }
61 mem_set(m, mesh_pipe_ring_sum(r, p), mesh_pipe_rec_sum_at(b, 4 * n, p));
62}
63static inline uint32_t mem_cell_word(mem *m, const mesh_pipe_ring *r, uint32_t p, size_t i) {
64 return mem_get(m, mesh_pipe_ring_cell(r, p) + 4 * i);
65}
66
67#endif