==> 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}