==> src/mailbox.c <==1/* mailbox.rs: checked atomic word, byte and window access. */
2#include "mesh/mailbox.h"
3#include "mesh/words_host.h"
4
5#include "mesh/abi/base.h"
6
7#include <stdatomic.h>
8#include <stdio.h>
9#include <stdlib.h>
10
11static _Noreturn void bad(size_t off) {
12 fprintf(stderr, "mailbox offset 0x%zx\n", off);
13 abort();
14}
15
16static _Atomic uint32_t *a32(mesh_mailbox m, size_t off) {
17 if (off % 4 != 0 || off + 4 > MESH_MAILBOX_BYTES) bad(off);
18 return (_Atomic uint32_t *)(void *)(m.base + off);
19}
20
21static _Atomic uint64_t *a64(mesh_mailbox m, size_t off) {
22 if (off % 8 != 0 || off + 8 > MESH_MAILBOX_BYTES) bad(off);
23 return (_Atomic uint64_t *)(void *)(m.base + off);
24}
25
26uint32_t mesh_mailbox_get(mesh_mailbox m, size_t off) { return atomic_load_explicit(a32(m, off), memory_order_acquire); }
27void mesh_mailbox_set(mesh_mailbox m, size_t off, uint32_t v) { atomic_store_explicit(a32(m, off), v, memory_order_relaxed); }
28void mesh_mailbox_publish(mesh_mailbox m, size_t off, uint32_t v) { atomic_store_explicit(a32(m, off), v, memory_order_release); }
29uint32_t mesh_mailbox_fetch_add(mesh_mailbox m, size_t off, uint32_t v) {
30 return atomic_fetch_add_explicit(a32(m, off), v, memory_order_acq_rel);
31}
32uint32_t mesh_mailbox_cas(mesh_mailbox m, size_t off, uint32_t cur, uint32_t desired) {
33 uint32_t seen = cur;
34 atomic_compare_exchange_strong_explicit(a32(m, off), &seen, desired, memory_order_acq_rel, memory_order_acquire);
35 return seen;
36}
37uint64_t mesh_mailbox_fetch_add64(mesh_mailbox m, size_t off, uint64_t v) {
38 return atomic_fetch_add_explicit(a64(m, off), v, memory_order_acq_rel);
39}
40uint8_t mesh_mailbox_get8(mesh_mailbox m, size_t off) {
41 if (off >= MESH_MAILBOX_BYTES) bad(off);
42 return atomic_load_explicit((_Atomic uint8_t *)(void *)(m.base + off), memory_order_acquire);
43}
44void mesh_mailbox_set8(mesh_mailbox m, size_t off, uint8_t v) {
45 if (off >= MESH_MAILBOX_BYTES) bad(off);
46 atomic_store_explicit((_Atomic uint8_t *)(void *)(m.base + off), v, memory_order_release);
47}
48uint64_t mesh_mailbox_get64(mesh_mailbox m, size_t off) { return atomic_load_explicit(a64(m, off), memory_order_acquire); }
49void mesh_mailbox_set64(mesh_mailbox m, size_t off, uint64_t v) { atomic_store_explicit(a64(m, off), v, memory_order_relaxed); }
50void mesh_mailbox_publish64(mesh_mailbox m, size_t off, uint64_t v) { atomic_store_explicit(a64(m, off), v, memory_order_release); }
51
52void mesh_mailbox_read(mesh_mailbox m, size_t off, uint8_t *out, size_t len) {
53 for (size_t w = 0; w < len; w += 4) {
54 uint32_t v = atomic_load_explicit(a32(m, off + w), memory_order_relaxed);
55 for (size_t i = 0; i < 4 && w + i < len; i++) out[w + i] = (uint8_t)(v >> (8 * i));
56 }
57}
58
59void mesh_mailbox_write(mesh_mailbox m, size_t off, const uint8_t *bytes, size_t n, size_t span) {
60 if (n > span) abort();
61 for (size_t w = 0; w < span; w += 4) {
62 uint32_t v = 0;
63 for (size_t i = 0; i < 4; i++)
64 if (w + i < n) v |= (uint32_t)bytes[w + i] << (8 * i);
65 atomic_store_explicit(a32(m, off + w), v, memory_order_relaxed);
66 }
67}
68
69void mesh_mailbox_zero(mesh_mailbox m, size_t off, size_t len) { mesh_mailbox_write(m, off, NULL, 0, len); }
70
71mesh_words mesh_mailbox_words(mesh_mailbox m) { return mesh_words_host(m.base); }
72
73mesh_mailbox mesh_mailbox_test(void) {
74 uint64_t *mem = calloc(MESH_MAILBOX_BYTES / 8, 8);
75 if (!mem) abort();
76 return mesh_mailbox_new((uint8_t *)mem, 0);
77}