==> tests/lease.c <==1/* The Rust's lease tests (mesh-host lease.rs), one for one: lanes sharing a ring and halting, a
2 * gated lane waiting for the blink, the bounded lockstep exchange. */
3#include "mesh/abi/base.h"
4#include "mesh/abi/control_block.h"
5#include "mesh/abi/exchange.h"
6#include "mesh/abi/fault.h"
7#include "mesh/abi/header.h"
8#include "mesh/abi/node.h"
9#include "mesh/abi/ring.h"
10#include "mesh/check.h"
11#include "mesh/lease.h"
12
13#include <pthread.h>
14#include <sched.h>
15#include <stdlib.h>
16#include <time.h>
17
18/* Squares the arg on node `first`; faults on op 9. */
19static size_t sq_max(void *self) {
20 (void)self;
21 return 4;
22}
23static bool sq_run(void *self, mesh_lease *l, const mesh_taken *taken, size_t n) {
24 (void)self;
25 for (size_t i = 0; i < n; i++) {
26 const mesh_taken *k = &taken[i];
27 if (k->op == 9) {
28 mesh_lease_fault(l, MESH_FAULT_TRAP | 7u << 8);
29 return false;
30 }
31 uint64_t t0 = mesh_host_ns();
32 mesh_lease_complete(l, l->first, k, k->arg * k->arg, t0, mesh_host_ns());
33 }
34 return true;
35}
36static const mesh_runner SQ = {sq_max, sq_run, NULL};
37
38typedef struct {
39 mesh_lease lease;
40 pthread_t th;
41 _Atomic bool done;
42 mesh_lane_stats stats;
43} lane;
44
45static void *lane_main(void *p) {
46 lane *x = p;
47 mesh_lease_run(&x->lease, &SQ, NULL);
48 return NULL;
49}
50
51static void publish(mesh_mailbox mb, uint32_t slot, uint32_t t, uint32_t op, uint32_t arg) {
52 size_t e = mesh_prog_ctl(slot) + MESH_P_RING + MESH_ENTRY_BYTES * (size_t)(t % MESH_PROG_RING);
53 mesh_mailbox_set(mb, e + MESH_E_OP, op);
54 mesh_mailbox_set(mb, e + MESH_E_ARG, arg);
55 mesh_mailbox_set(mb, e + MESH_E_SLOT, t % MESH_PROG_RESULTS);
56 mesh_mailbox_publish(mb, e + MESH_E_SEQ, t + 1);
57}
58
59static uint32_t ctl(mesh_mailbox mb, uint32_t slot, size_t off) { return mesh_mailbox_get(mb, mesh_prog_ctl(slot) + off); }
60
61static void lanes_share_a_ring_and_halt(void) {
62 mesh_mailbox mb = mesh_mailbox_test();
63 uint32_t slot = 3;
64 lane lanes[3] = {0};
65 for (uint32_t n = 0; n < 3; n++) {
66 mesh_lease_init(&lanes[n].lease, mb, slot, n, 1, false, &lanes[n].done, &lanes[n].stats);
67 pthread_create(&lanes[n].th, NULL, lane_main, &lanes[n]);
68 }
69 while (ctl(mb, slot, MESH_P_ONLINE) < 3) sched_yield();
70 /* H_BLINK does not hold ungated lanes. */
71 mesh_mailbox_set(mb, MESH_H_BLINK, 1);
72 /* At most a ring of tickets in flight (as the publisher keeps it). */
73 uint64_t t0 = mesh_host_ns();
74 for (uint32_t t = 0; t < 200; t++) {
75 size_t mark = MESH_P_MARKS + 4 * (size_t)(t % MESH_PROG_RESULTS);
76 while (t >= MESH_PROG_RING && ctl(mb, slot, mark) != t - MESH_PROG_RING + 1) {
77 CHECK(mesh_host_ns() - t0 < 5000000000ull);
78 sched_yield();
79 }
80 publish(mb, slot, t, 0, t);
81 }
82 while (ctl(mb, slot, MESH_P_DONE) < 200) {
83 if (!CHECK(mesh_host_ns() - t0 < 5000000000ull)) break;
84 sched_yield();
85 }
86 for (uint32_t t = 0; t < 200; t++) {
87 size_t c = t % MESH_PROG_RESULTS;
88 if (t + MESH_PROG_RESULTS >= 200) {
89 CHECK_U(ctl(mb, slot, MESH_P_MARKS + 4 * c), t + 1);
90 CHECK_U(ctl(mb, slot, MESH_P_RESULTS + 4 * c), t * t);
91 }
92 }
93 uint32_t tasks = 0;
94 for (uint32_t n = 0; n < 3; n++) tasks += mesh_mailbox_get(mb, mesh_node_rec(slot, n) + MESH_N_TASKS);
95 CHECK_U(tasks, 200);
96 CHECK_U(ctl(mb, slot, MESH_P_RING_HEAD), 200);
97 CHECK_U(ctl(mb, slot, MESH_P_TRACE_N), 200);
98 /* A fault: recorded once, the ticket left incomplete; then shutdown halts every lane. */
99 publish(mb, slot, 200, 9, 0);
100 while (ctl(mb, slot, MESH_P_FAULT) == 0) sched_yield();
101 CHECK_U(ctl(mb, slot, MESH_P_FAULT), MESH_FAULT_TRAP | 7u << 8);
102 mesh_mailbox_publish(mb, mesh_prog_ctl(slot) + MESH_P_SHUTDOWN, 1);
103 for (uint32_t n = 0; n < 3; n++) {
104 pthread_join(lanes[n].th, NULL);
105 CHECK(atomic_load(&lanes[n].done));
106 }
107 CHECK_U(ctl(mb, slot, MESH_P_HALTED), 3);
108 CHECK_U(ctl(mb, slot, MESH_P_DONE), 200);
109 free(mb.base);
110}
111
112static void gated_lane_waits_for_the_blink(void) {
113 mesh_mailbox mb = mesh_mailbox_test();
114 mesh_mailbox_set(mb, MESH_H_BLINK, 1);
115 lane x = {0};
116 mesh_lease_init(&x.lease, mb, 0, 0, 2, true, &x.done, &x.stats);
117 pthread_create(&x.th, NULL, lane_main, &x);
118 publish(mb, 0, 0, 0, 5);
119 struct timespec ms20 = {0, 20000000};
120 nanosleep(&ms20, NULL);
121 CHECK_U(ctl(mb, 0, MESH_P_ONLINE), 2);
122 CHECK_U(ctl(mb, 0, MESH_P_DONE), 0);
123 mesh_mailbox_set(mb, MESH_H_BLINK, 0);
124 while (ctl(mb, 0, MESH_P_DONE) < 1) sched_yield();
125 CHECK_U(ctl(mb, 0, MESH_P_RESULTS), 25);
126 mesh_mailbox_publish(mb, mesh_prog_ctl(0) + MESH_P_SHUTDOWN, 1);
127 pthread_join(x.th, NULL);
128 CHECK_U(ctl(mb, 0, MESH_P_HALTED), 2);
129 free(mb.base);
130}
131
132static void exchange_waits_bounded(void) {
133 mesh_mailbox mb = mesh_mailbox_test();
134 lane x = {0};
135 mesh_lease_init(&x.lease, mb, 0, 0, 1, false, &x.done, &x.stats);
136 CHECK_U(mesh_lease_exchange(&x.lease, 1), MESH_ROUND_TIMEOUT); /* single: no round */
137 mesh_mailbox_set(mb, MESH_H_GROUP_RANK, 1);
138 mesh_mailbox_set(mb, MESH_H_GROUP_N, 2);
139 mesh_mailbox_publish64(mb, mesh_ex_counter(0), 4);
140 CHECK_U(mesh_lease_exchange(&x.lease, 3), MESH_ROUND_OK);
141 CHECK_U(mesh_mailbox_get64(mb, mesh_ex_counter(1)), 3);
142 uint64_t t0 = mesh_host_ns();
143 CHECK_U(mesh_lease_exchange(&x.lease, 5), MESH_ROUND_TIMEOUT);
144 CHECK(mesh_host_ns() - t0 >= (uint64_t)MESH_PEER_POLLS * MESH_PEER_POLL_NS);
145 CHECK_U(atomic_load(&x.stats.rounds), 3);
146 free(mb.base);
147}
148
149int main(void) {
150 lanes_share_a_ring_and_halt();
151 gated_lane_waits_for_the_blink();
152 exchange_waits_bounded();
153 return mesh_check_done();
154}