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