#ifndef VMSIG_CONTROL_H #define VMSIG_CONTROL_H #include "vmsig_event.h" /* vmsig_control.h — control-agnostic seam. Control (an algorithm OR a human) * attaches via ONE neutral interface: a command queue (down) + an event * subscription (up). In-process implements the vtable with direct callbacks * (fd = -1); out-of-process is a socket whose fd is registered with the core like * any source. The core treats both the same. Orchestration is NOT wired in here — * only the seam. */ /* Subscription filter: which UP events the control WANTS. This is only a * NARROWING; the real ceiling is set by the grant (effective = sub ∩ grant). */ typedef struct { uint32_t source_mask; /* bit (1u< not a valid poller (receives and * sends nothing). */ #define VMSIG_CAP_OBSERVE 0x1u /* UP of SEAM/generic coherent state (observation) */ #define VMSIG_CAP_INPUT 0x2u /* CMD_INPUT */ /* (0x4 is the freed bit of the removed CAP_STREAM; the future vgpu-control down-path * returns via write-signaled/MEMWRITE. Do NOT reuse.) */ #define VMSIG_CAP_LIFECYCLE 0x8u /* CMD_LIFECYCLE safe ones (pause/resume/wakeup) */ /* (0x10 is the freed bit of the removed CAP_MEMREAD; do NOT reuse: a stale grant * with this bit must not silently alias to the privileged memory cap.) */ #define VMSIG_CAP_POWER 0x20u /* destructive lifecycle/VM (powerdown/reset/quit) */ #define VMSIG_CAP_VM 0x40u /* CMD_VM safe ones (query/cont/stop), VMHOST seam */ #define VMSIG_CAP_MEMCTX 0x80u /* SUBSCRIPTION to a coherent AS context (UP MEMCTX*, re-share RO-fd). * NOT an access broker (that is OS-DAC on the fd) — gates RECEIVING the datum. */ #define VMSIG_CAP_MEMWRITE 0x100u /* CMD_MEMWRITE: atomic write-signaled mutation of shared guest memory * (separate from the freed CAP_MEMREAD bit — read != write; fresh bit * avoids stale-grant aliasing to this privileged cap). */ typedef struct { uint32_t principal; /* id for auditing (uid/token) */ uint64_t endpoint_mask; /* which VMs (bit 1ull< * PREEMPT, otherwise DENY. */ typedef enum { VMSIG_ARB_DENY = 0, /* deny the contender, the owner keeps it */ VMSIG_ARB_PREEMPT = 1 /* take it from the owner, give it to the contender (QUEUE — reserved) */ } vmsig_arb_decision; /* Called ONLY when (endpoint,class) is held by a LIVE owner (incumbent) and an * ACQUIRE arrives from another contender. incumbent/contender are the parties' * grants (live, not copies); incumbent is NEVER NULL (a dead owner is treated as a * free slot and policy is not called). Called on the loop thread. */ typedef vmsig_arb_decision (*vmsig_arb_policy)(void* ud, uint32_t endpoint, uint32_t cls, const vmsig_grant* incumbent, const vmsig_grant* contender); /* Control endpoint vtable. The core calls deliver() for UP; control sends DOWN via * the emit hook that the core installs in set_emit_down(). */ typedef struct vmsig_control_ops { const char* name; /* fd for an out-of-process control (socket). -1 => in-process, callbacks only * (no registration in epoll). */ int (*fd)(void* ctl); /* Declare interest (called once at attach). */ int (*subscribe)(void* ctl, vmsig_sub* out); /* Core -> control: an UP event for the subscriber. For in-process, a direct * call; for socket-control, serialization onto the wire. Borrowed: whatever * must outlive the call must be copied. */ int (*deliver)(void* ctl, const vmsig_event* ev); /* Core -> control (socket only): the control-fd is readable; the implementation * parses the wire into DOWN events and calls the installed down-emit. */ int (*on_readable)(void* ctl); /* The core installs the hook by which control sends DOWN commands; the core * routes them into vmsig_ctx_submit(ctx, VMSIG_DIR_DOWN, ev). */ void (*set_emit_down)(void* ctl, int (*emit)(void* token, vmsig_event*), void* token); void (*close)(void* ctl); /* Core -> control: deliver a coherent address-space context (UP MEMCTX) + RO-fd * of the RAM region. Socket: a vmsig_wire frame (kind=MEMCTX, inln=vmsig_memctx) + fd in cmsg * (SCM_RIGHTS); the segs payload does NOT go on the wire (the holder opens * via `low`). In-proc: direct fd + event (segs in payload, decode with vmsig_memctx_segs). * The fd is BORROWED for the duration of the call (the core closes it afterwards) — the holder * dup's/mmap's it to keep it. Optional: NULL => control does not accept MEMCTX. 0/-1. */ int (*attach_memctx)(void* ctl, const vmsig_event* ev, int fd); } vmsig_control_ops; /* Reference in-process control: a thin shim turning a C callback into a vtable, for * embedding an algorithm directly. */ typedef struct { int (*on_event)(void* user, const vmsig_event* up); /* core -> algorithm */ void* user; vmsig_sub sub; /* subscription filter */ /* Core -> algorithm: a coherent AS context (UP MEMCTX) + RO-fd as a direct int. The fd * is borrowed (dup/mmap to keep it). NULL => does not accept. 0/-1. */ int (*on_memctx)(void* user, const vmsig_event* ev, int fd); } vmsig_inproc_cfg; /* Create a reference in-proc control over cfg (which is copied). Returns an opaque * ctl for vmsig_core_add_control(core, vmsig_inproc_control_ops(), ctl). Freed via * ops->close(ctl). NULL on OOM. */ const vmsig_control_ops* vmsig_inproc_control_ops(void); void* vmsig_inproc_control_new(const vmsig_inproc_cfg* cfg); /* Send a DOWN command from an in-proc control (after attach). 0 — ok, -1 — error. */ int vmsig_inproc_send(void* ctl, vmsig_event* down); #endif /* VMSIG_CONTROL_H */