skip to content
==> src/prog_table.c <==
1/* The program table writer: the PT_GEN seqlock around every rewrite. */
2#include "mesh/prog_table.h"
3
4#include <stdatomic.h>
5#include <string.h>
6
7static uint32_t word(const uint8_t *b, size_t at) {
8    return (uint32_t)b[at] | (uint32_t)b[at + 1] << 8 | (uint32_t)b[at + 2] << 16 | (uint32_t)b[at + 3] << 24;
9}
10
11static uint32_t gen_odd(mesh_mailbox mb, size_t e) {
12    uint32_t gen = mesh_mailbox_get(mb, e + MESH_PT_GEN) | 1u;
13    mesh_mailbox_set(mb, e + MESH_PT_GEN, gen);
14    atomic_thread_fence(memory_order_seq_cst);
15    return gen;
16}
17
18void mesh_pt_write_entry(mesh_mailbox mb, uint32_t s, const uint8_t entry[MESH_PT_BYTES], const uint8_t ext[MESH_PX_BYTES],
19                         uint32_t state) {
20    size_t e = mesh_prog_entry(s);
21    uint32_t gen = gen_odd(mb, e);
22    for (size_t at = MESH_PT_NAME; at < MESH_PT_BYTES; at += 4) mesh_mailbox_set(mb, e + at, word(entry, at));
23    for (size_t at = 0; at < MESH_PX_BYTES; at += 4) mesh_mailbox_set(mb, mesh_prog_ext(s) + at, word(ext, at));
24    mesh_mailbox_set(mb, e + MESH_PT_STATE, state);
25    mesh_mailbox_publish(mb, e + MESH_PT_GEN, gen + 1);
26    mesh_mailbox_fetch_add(mb, MESH_H_PROG_SEQ, 1);
27}
28
29void mesh_pt_set_state(mesh_mailbox mb, uint32_t s, uint32_t state) {
30    if (mesh_mailbox_get(mb, mesh_prog_entry(s) + MESH_PT_STATE) == state) return;
31    mesh_mailbox_publish(mb, mesh_prog_entry(s) + MESH_PT_STATE, state);
32    mesh_mailbox_fetch_add(mb, MESH_H_PROG_SEQ, 1);
33}
34
35void mesh_pt_clear(mesh_mailbox mb, uint32_t s) {
36    static const uint8_t zero_e[MESH_PT_BYTES], zero_x[MESH_PX_BYTES], zero_p[MESH_PP_BYTES];
37    mesh_pt_write_entry(mb, s, zero_e, zero_x, MESH_ST_EMPTY);
38    mesh_pt_write_pipe(mb, s, zero_p);
39}
40
41static int ours(size_t i) { return 4 * i != MESH_PP_FLIGHT && 4 * i != MESH_PP_FLIGHT1; }
42
43void mesh_pt_write_pipe(mesh_mailbox mb, uint32_t s, const uint8_t b[MESH_PP_BYTES]) {
44    size_t e = mesh_prog_entry(s), p = mesh_pipe_entry(s);
45    int same = 1;
46    for (size_t i = 0; i < MESH_PP_BYTES / 4 && same; i++)
47        if (ours(i) && mesh_mailbox_get(mb, p + 4 * i) != word(b, 4 * i)) same = 0;
48    if (same) return;
49    uint32_t gen = gen_odd(mb, e);
50    for (size_t i = 0; i < MESH_PP_BYTES / 4; i++) if (ours(i)) mesh_mailbox_set(mb, p + 4 * i, word(b, 4 * i));
51    mesh_mailbox_publish(mb, e + MESH_PT_GEN, gen + 1);
52}
53
54void mesh_pt_set_hold(mesh_mailbox mb, uint32_t s, bool on) {
55    size_t e = mesh_prog_entry(s);
56    uint32_t gen = gen_odd(mb, e);
57    mesh_mailbox_set(mb, mesh_pipe_entry(s) + MESH_PP_IN_HOLD, on);
58    mesh_mailbox_publish(mb, e + MESH_PT_GEN, gen + 1);
59    atomic_thread_fence(memory_order_seq_cst);
60}
61
62uint32_t mesh_pt_flight(mesh_mailbox mb, uint32_t s, uint32_t parity) { return mesh_mailbox_get(mb, mesh_flight_word(s, parity)); }
63
64uint32_t mesh_pt_flight_epoch(mesh_mailbox mb) {
65    uint32_t old = mesh_mailbox_get(mb, MESH_H_PIPE_EPOCH);
66    mesh_mailbox_publish(mb, MESH_H_PIPE_EPOCH, old + 1);
67    atomic_thread_fence(memory_order_seq_cst);
68    return old & 1u;
69}
70
71void mesh_pt_flight_clear(mesh_mailbox mb, uint32_t s) {
72    mesh_mailbox_set(mb, mesh_flight_word(s, 0), 0);
73    mesh_mailbox_set(mb, mesh_flight_word(s, 1), 0);
74}
75
76void mesh_pt_reset_slot(mesh_mailbox mb, uint32_t s) {
77    mesh_mailbox_zero(mb, mesh_prog_ctl(s), MESH_P_RUN_REQ);
78    mesh_mailbox_zero(mb, mesh_prog_ctl(s) + MESH_P_RUN_REQ + 4, MESH_PROG_CTL_BYTES - MESH_P_RUN_REQ - 4);
79    mesh_mailbox_zero(mb, mesh_node_rec(s, 0), MESH_PROG_NODES_BYTES);
80    mesh_mailbox_zero(mb, mesh_node_load(s, 0), (size_t)MESH_NL_STRIDE * MESH_PROG_MAX_NODES);
81    mesh_mailbox_zero(mb, mesh_trace_rec(s, 0), (size_t)MESH_TRACE_BYTES * MESH_TRACE_PER_PROG);
82    mesh_pt_flight_clear(mb, s);
83}
84
85void mesh_pt_name_of(mesh_mailbox mb, uint32_t s, char out[MESH_NAME_BYTES + 1]) {
86    mesh_mailbox_read(mb, mesh_prog_entry(s) + MESH_PT_NAME, (uint8_t *)out, MESH_NAME_BYTES);
87    out[MESH_NAME_BYTES] = 0;
88}
89
90bool mesh_pt_find(mesh_mailbox mb, const char *name, uint32_t *slot) {
91    for (uint32_t s = 0; s < MESH_PROG_SLOTS; s++) {
92        if (mesh_mailbox_get(mb, mesh_prog_entry(s) + MESH_PT_STATE) == MESH_ST_EMPTY) continue;
93        char n[MESH_NAME_BYTES + 1];
94        mesh_pt_name_of(mb, s, n);
95        if (strcmp(n, name) == 0) { *slot = s; return true; }
96    }
97    return false;
98}
99
100void mesh_pt_read_entry(mesh_mailbox mb, uint32_t s, uint8_t out[MESH_PT_BYTES]) {
101    size_t e = mesh_prog_entry(s);
102    for (;;) {
103        uint32_t g = mesh_mailbox_get(mb, e + MESH_PT_GEN);
104        if ((g & 1u) == 0) {
105            mesh_mailbox_read(mb, e, out, MESH_PT_BYTES);
106            atomic_thread_fence(memory_order_seq_cst);
107            if (mesh_mailbox_get(mb, e + MESH_PT_GEN) == g) return;
108        }
109    }
110}