skip to content
==> tests/harness.h <==
1/* A slot of a test mailbox, its ticket ring from the host side, and its nodes
2 * on a thread (exec's mesh_worker_run_nodes), for native programs' tests. */
3#ifndef NATIVE_TEST_HARNESS_H
4#define NATIVE_TEST_HARNESS_H
5#include "mesh/abi/control_block.h"
6#include "mesh/abi/ops.h"
7#include "mesh/abi/pipe_table.h"
8#include "mesh/abi/program_table.h"
9#include "mesh/abi/ring.h"
10#include "mesh/abi/pipe_hash.h"
11#include "mesh/check.h"
12#include "mesh/mailbox.h"
13#include "mesh/worker_node.h"
14
15#include <pthread.h>
16#include <sched.h>
17#include <stdlib.h>
18#include <string.h>
19#include <time.h>
20
21static inline void h_install(mesh_mailbox mb, uint32_t s, const char *name, uint32_t nodes, uint32_t view_off, uint32_t view_bytes) {
22    size_t e = mesh_prog_entry(s);
23    const uint32_t kv[][2] = {{MESH_PT_VIEW_OFF, view_off}, {MESH_PT_VIEW_BYTES, view_bytes}, {MESH_PT_NODES, nodes}, {MESH_PT_STATE, MESH_ST_RUNNING}};
24    for (size_t i = 0; i < 4; i++) mesh_mailbox_set(mb, e + kv[i][0], kv[i][1]);
25    uint8_t n[16] = {0};
26    memcpy(n, name, strlen(name));
27    mesh_mailbox_write(mb, e + MESH_PT_NAME, n, 16, 16);
28}
29static inline void h_inbox(mesh_mailbox mb, uint32_t s, uint32_t off, uint32_t cap, uint32_t rec, const char *type) {
30    size_t p = mesh_pipe_entry(s);
31    mesh_mailbox_set(mb, p + MESH_PP_IN_OFF, off);
32    mesh_mailbox_set(mb, p + MESH_PP_IN_CAP, cap);
33    mesh_mailbox_set(mb, p + MESH_PP_IN_REC, rec);
34    mesh_mailbox_set(mb, p + MESH_PP_IN_TYPE, mesh_pipe_type_hash((const uint8_t *)type, strlen(type)));
35}
36static inline void h_feed(mesh_mailbox mb, uint32_t from, uint32_t to) {
37    size_t p = mesh_pipe_entry(from);
38    mesh_mailbox_set(mb, p + MESH_PP_FEEDS_MASK, mesh_mailbox_get(mb, p + MESH_PP_FEEDS_MASK) | 1u << to);
39}
40
41typedef struct {
42    mesh_mailbox mb;
43    uint32_t slot, next;
44    mesh_worker_program prog;
45    atomic_bool stop;
46    pthread_t th;
47} h_slot;
48
49static inline void *h_runner(void *a) {
50    h_slot *h = a;
51    mesh_worker_run_nodes(h->mb, h->slot, &h->prog, &h->stop);
52    return NULL;
53}
54static inline void h_start(h_slot *h) {
55    atomic_store(&h->stop, false);
56    pthread_create(&h->th, NULL, h_runner, h);
57}
58static inline void h_stop(h_slot *h) {
59    mesh_mailbox_publish(h->mb, mesh_prog_ctl(h->slot) + MESH_P_SHUTDOWN, MESH_SHUTDOWN_HALT);
60    pthread_join(h->th, NULL);
61}
62static inline uint32_t h_call(h_slot *h, uint32_t op, uint32_t arg) {
63    uint32_t t = h->next++;
64    size_t c = mesh_prog_ctl(h->slot), e = c + MESH_P_RING + MESH_ENTRY_BYTES * (t % MESH_PROG_RING), k = t % MESH_PROG_RESULTS;
65    mesh_mailbox_set(h->mb, e + MESH_E_OP, op);
66    mesh_mailbox_set(h->mb, e + MESH_E_ARG, arg);
67    mesh_mailbox_set(h->mb, e + MESH_E_SLOT, (uint32_t)k);
68    mesh_mailbox_publish(h->mb, e + MESH_E_SEQ, t + 1);
69    struct timespec t0, now;
70    clock_gettime(CLOCK_MONOTONIC, &t0);
71    while (mesh_mailbox_get(h->mb, c + MESH_P_MARKS + 4 * k) != t + 1) {
72        clock_gettime(CLOCK_MONOTONIC, &now);
73        if (now.tv_sec - t0.tv_sec > 60) { fprintf(stderr, "ticket %u never completed\n", t); abort(); }
74        sched_yield();
75    }
76    return mesh_mailbox_get(h->mb, c + MESH_P_RESULTS + 4 * k);
77}
78#endif