#ifndef VMSIG_ADAPTER_H #define VMSIG_ADAPTER_H #include "vmsig_event.h" #include "vmsig_memctx.h" /* vmsig_memctx_reg — address-space context registration seam */ /* vmsig_adapter.h — unified SI adapter interface. One vtable, three readiness * shapes behind it. The adapter is the ONLY place that includes neighbor headers * (memmodel.h/win32.h/vgpu_stream.h/vmctl.h). It registers 0..N fds with the core; * the core does not know whether it is a socket, eventfd or timerfd. SI specifics * never leave these functions. */ typedef struct vmsig_adapter vmsig_adapter; /* opaque adapter instance */ /* How the adapter expresses readiness. The core treats all three as ordinary * epoll fds; the enum is documentation + the choice of default epoll flags. */ typedef enum { VMSIG_RDY_FD = 0, /* native pollable fd (socket) */ VMSIG_RDY_TIMERFD = 1, /* timerfd; adapter samples shared memory */ VMSIG_RDY_EVENTFD = 2 /* worker thread bridges a blocking API -> eventfd */ } vmsig_readiness; /* Sink handed by the core to the adapter for emitting UP events without knowing * the internals of the context. emit() is thread-safe (also called from worker * threads); register_memctx/unregister_memctx are called ONLY on the loop thread. * The registration hooks may be NULL (adapters/tests need not call them). */ typedef struct { int (*emit)(void* token, vmsig_event* ev); /* UP (thread-safe) */ int (*register_memctx)(void* token, const vmsig_memctx_reg* reg); /* loop thread: AS context; 0/-1 */ void (*unregister_memctx)(void* token, uint32_t endpoint); /* loop thread: context gone */ void* token; } vmsig_emit; /* One fd contributed by the adapter, with epoll flags and a cookie for demux. */ typedef struct { int fd; uint32_t epoll_events; /* EPOLLIN / EPOLLOUT / ... */ vmsig_readiness shape; uint32_t cookie; /* adapter-private fd discriminator */ } vmsig_fd_reg; /* Adapter vtable. Each SI adapter implements this; SI specifics do not leak. */ typedef struct vmsig_adapter_ops { const char* name; /* "memctx"/"input"/"vmhost" — diagnostics */ vmsig_source source; /* neutral seam role */ uint32_t codec; /* vmsig_codec owned by the adapter */ /* Create an instance from opaque cfg (adapter parses it; core passes as-is). * Returns an instance or NULL. `endpoint` is the id of the VM it binds to. */ vmsig_adapter* (*open)(const void* cfg, uint32_t endpoint); /* Attach: open the SI contract, bring up workers, hand fds into reg[] * (<=cap), store `emit` for UP. Returns the number of registered fds (>=0) / -1. */ int (*attach)(vmsig_adapter* a, const vmsig_emit* emit, vmsig_fd_reg* reg, int cap); /* Readiness of one of the adapter's fds: `cookie` identifies the fd, `events` * are the epoll flags. The adapter does NON-blocking work (reads the socket / * drains the eventfd / reads the timerfd + samples counters) and calls emit on * each UP. 0 — ok, -1 — fatal (the core detaches the adapter). */ int (*on_readiness)(vmsig_adapter* a, uint32_t cookie, uint32_t events); /* Consume a DOWN event (a control decision): encode it into the contract * (vmctl_batch / vmctl power; write the vgpu control block; read request to vmie). * For blocking sinks it hands the work to a worker and returns immediately; * completion arrives later as an UP VMSIG_EV_ACT_ACK (keyed by ev->corr). * 0 — accepted, 1 — rejected (not for this seam), -1 — error. */ int (*submit)(vmsig_adapter* a, const vmsig_event* ev); /* Detach + free: stop workers, close SI handles and fds. */ void (*close)(vmsig_adapter* a); } vmsig_adapter_ops; /* Factories (defined in each adapter's TU — the only symbol the build/cli layer * needs; keeps neighbor headers out of the core's include-path). */ const vmsig_adapter_ops* vmsig_memctx_ops(void); /* vmie: address-space context (kcr3+locator) */ const vmsig_adapter_ops* vmsig_input_ops(void); /* vmctl */ const vmsig_adapter_ops* vmsig_vmhost_ops(void); /* QEMU/QMP (its own signaling) */ /* (vgpu frame sensor is no longer a signaling adapter: vgpu perception lives in an * out-of-repo S-lib that consumes memctx; see vgpu-perception-handoff.) */ #endif /* VMSIG_ADAPTER_H */