Files
vatrog-vm-signaling/src/test/test_dynep.c
T
lirent 9bde398b6c vmsig: management daemon, runtime endpoint lifecycle, roster, discovery, in-tree drivers, packaging
- core: runtime attach/detach of a per-endpoint adapter trio (runtime-safe add_adapter + vmsig_core_detach_endpoint, deferred reap)
- roster: VMSIG_EV_ROSTER + CAP_ROSTER, retained per-endpoint and replayed to late subscribers
- discovery: inotify trigger dir, vmid/endpoint slot allocator, host probe; vmsigd daemon with config + per-uid admission
- input driver and vgpu perception built in-tree; vgpu perception as a separate library
- memctx: own the supplied ro_fd (closed at detach)
- deb packaging: install rules, systemd unit, tmpfiles, default config
2026-06-22 17:25:06 +03:00

101 lines
4.0 KiB
C

/* test_dynep.c — runtime hot-plug of a VM endpoint (WS1): a discovery-style consumer
* attaches an adapter trio, then detaches it and re-attaches it on the SAME endpoint
* while the loop is running. Proves:
* - vmsig_core_add_adapter works AFTER vmsig_core_run started (from a loop-thread cb);
* - vmsig_core_detach_endpoint tears the trio down (deferred reap) and bumps the epoch,
* broadcasting MEMCTX_INVALIDATED so a holder settles;
* - re-attaching the same endpoint publishes MEMCTX at the strictly-higher epoch.
* All driven from the holder callbacks, which run on the loop thread (single-threaded
* with the pumps), so attach/detach are issued mid-loop exactly as discovery will. */
#define _GNU_SOURCE
#include "vmsig.h"
#include <stdio.h>
#include <string.h>
#include <stdint.h>
static int g_fail = 0;
#define CHECK(cond, msg) do { \
if (!(cond)) { printf(" FAIL: %s\n", (msg)); g_fail = 1; } \
} while (0)
typedef struct {
vmsig_core* core;
uint32_t ep;
int memctx; /* MEMCTX received */
int invalidated; /* MEMCTX_INVALIDATED received */
uint32_t last_epoch; /* epoch of the last MEMCTX */
int phase; /* 0: pre-detach, 1: detached, 2: reattached */
int ticks; /* vmhost watchdog ticks (failsafe) */
} dyn;
/* Re-attach the trio (vmhost watchdog + memctx) on the same endpoint, mid-loop, from the
* INVALIDATED delivery — exactly the discovery "file reappeared" path. */
static void reattach_trio(dyn* d) {
vmsig_core_add_adapter(d->core, vmsig_vmhost_ops(), NULL, d->ep);
vmsig_core_add_adapter(d->core, vmsig_memctx_ops(), NULL, d->ep);
}
static int dyn_on_ev(void* u, const vmsig_event* ev) {
dyn* d = u;
if (ev->kind == VMSIG_EV_VM_LIFECYCLE) d->ticks++;
else if (ev->kind == VMSIG_EV_MEMCTX_INVALIDATED) {
d->invalidated++;
if (d->phase == 1) { d->phase = 2; reattach_trio(d); }
}
if (d->ticks > 60) vmsig_core_stop(d->core); /* failsafe */
return 0;
}
static int dyn_on_memctx(void* u, const vmsig_event* ev, int fd) {
dyn* d = u;
const vmsig_memctx* m = (const vmsig_memctx*)ev->inln;
(void)fd; /* core closes the borrowed RO-fd after this call */
d->memctx++;
d->last_epoch = m->epoch;
if (d->phase == 0 && m->epoch == 0) {
d->phase = 1;
vmsig_core_detach_endpoint(d->core, d->ep); /* deferred reap -> bump -> INVALIDATED */
} else if (d->phase == 2 && m->epoch >= 1) {
vmsig_core_stop(d->core); /* re-attached context observed: done */
}
return 0;
}
static void test_dynep(void) {
printf("test_dynep\n");
vmsig_ctx* ctx = vmsig_ctx_new();
vmsig_core* core = vmsig_core_new(ctx);
dyn d; memset(&d, 0, sizeof d);
d.core = core; d.ep = 0;
vmsig_inproc_cfg cfg; memset(&cfg, 0, sizeof cfg);
cfg.on_event = dyn_on_ev; cfg.on_memctx = dyn_on_memctx; cfg.user = &d;
void* ctl = vmsig_inproc_control_new(&cfg);
vmsig_grant g; memset(&g, 0, sizeof g);
g.principal = 1; g.endpoint_mask = 1ull << 0; g.source_mask = 0xFFFFFFFFu;
g.cap_mask = VMSIG_CAP_MEMCTX | VMSIG_CAP_OBSERVE;
vmsig_core_add_control(core, vmsig_inproc_control_ops(), ctl, &g);
/* initial trio on ep0, pre-run (vmhost watchdog ticks the loop + memctx publishes). */
CHECK(vmsig_core_add_adapter(core, vmsig_vmhost_ops(), NULL, 0) >= 0, "add vmhost ep0");
CHECK(vmsig_core_add_adapter(core, vmsig_memctx_ops(), NULL, 0) >= 0, "add memctx ep0");
vmsig_core_run(core);
CHECK(d.memctx >= 2, "MEMCTX received before AND after re-attach");
CHECK(d.invalidated >= 1, "MEMCTX_INVALIDATED delivered on detach");
CHECK(d.last_epoch >= 1, "epoch advanced across detach/re-attach");
CHECK(d.phase == 2, "reached the re-attached phase");
vmsig_core_free(core);
vmsig_ctx_free(ctx);
}
int main(void) {
test_dynep();
printf("dynep tests: %s\n", g_fail ? "FAIL" : "PASS");
return g_fail ? 1 : 0;
}