#ifndef VMSIG_CORE_INTERNAL_H #define VMSIG_CORE_INTERNAL_H #include "vmsig_core.h" #include /* Private internals of the epoll core. Each registered fd carries a * core_slot* in epoll_event.data.ptr; the slot's role decides how to handle it. */ #define VMSIG_MAX_EVENTS 64 #define VMSIG_MAX_ADAPTERS 256 /* up to ~64 VMs * 3 adapters + slack (mode A) */ #define VMSIG_MAX_CONTROLS 64 /* concurrent pollers; more => processes (C) */ #define VMSIG_ADAPTER_FDS 8 /* max fds per adapter */ #define VMSIG_DOWN_PENDING_MAX 256 /* ceiling of DOWN commands per poller in ctx (fairness) */ typedef enum { SLOT_WAKEUP, /* wake/stop eventfd */ SLOT_ADAPTER, /* adapter fd (timerfd/eventfd/socket) */ SLOT_CTX_TIMING, /* context pacing timerfd */ SLOT_CONTROL, /* out-of-process control socket */ SLOT_SOURCE, /* arbitrary fd + callback (e.g. listen-fd) */ SLOT_DEAD /* detached (reaped); loop ignores it */ } slot_role; typedef struct core_slot { slot_role role; int fd; /* for SLOT_ADAPTER */ const vmsig_adapter_ops* ops; vmsig_adapter* adapter; uint32_t cookie; /* for SLOT_CONTROL */ const vmsig_control_ops* cops; void* ctl; /* for SLOT_SOURCE */ void (*on_source)(void* user, uint32_t events); void (*on_free)(void* user); /* invoked at core_free (source cleanup) */ void* source_user; } core_slot; typedef struct { const vmsig_adapter_ops* ops; vmsig_adapter* a; uint32_t endpoint; } core_adapter_ent; /* ===== Retained address-space context (MEMCTX seam) ===== * The core retains per-endpoint "a current context exists in the current epoch" + the * adapter's reg pointer (describe/share_fd/invalidate). Replays to a late qualified * subscriber (CAP_MEMCTX + source_mask + endpoint) re-sharing the RO-fd. Does NOT store a * copy of the locator: on delivery/replay it calls reg.describe (adapter snapshot) + * reg.share_fd (fresh RO-fd). Invalidated on epoch change; cleared on unregister/free. */ typedef struct { int registered; /* adapter called register_memctx (reg valid) */ int valid; /* a published context exists in the current epoch */ uint32_t epoch; /* snapshot epoch (== core epoch[ep] when valid) */ vmsig_memctx_reg reg; /* valid when registered */ } core_memctx_cell; /* ===== Lease layer (arbitration of exclusive ownership of destructive resources) ===== * One cell per (endpoint, lease-class): who owns it (origin) + a snapshot of arb_prio at * acquisition time. owner=0 => free. The snapshot (rather than the live grant) makes the * policy resilient to the owner's grant changing after acquisition. */ #define VMSIG_LEASE_CLASSES 3 /* INPUT, POWER, MEMWRITE (== VMSIG_LEASE_CLASS_MAX) */ typedef struct { uint32_t owner; /* origin (gen<<16)|(id+1) of the owner; 0 = free */ uint32_t owner_prio; /* owner's arb_prio at acquisition time (snapshot) */ } core_lease_cell; struct vmsig_core; /* fwd for core_down_ctx */ /* DOWN emission context: handed to a control in set_emit_down so emit_down knows WHICH * control issued the command (for grant lookup and enforcement). Stable: lives in the * fixed controls[] array. */ typedef struct { struct vmsig_core* core; int ctl_id; } core_down_ctx; typedef struct { const vmsig_control_ops* ops; void* ctl; vmsig_sub sub; vmsig_grant grant; /* poller's rights ceiling (default-deny) */ core_down_ctx dctx; /* token for emit_down */ int active; /* 0 = detached/reaped (slot free) */ int reap; /* reap requested (deferred) */ core_slot* slot; /* SLOT_CONTROL fd slot (or NULL) */ uint32_t pending; /* DOWN commands of this poller in ctx (fairness cap) */ uint16_t gen; /* slot generation: +1 on each (re)use */ } core_control_ent; struct vmsig_core { int epfd; int wake_fd; /* eventfd: nudge + stop */ vmsig_ctx* ctx; volatile sig_atomic_t stopping; core_adapter_ent adapters[VMSIG_MAX_ADAPTERS]; int nadapters; core_control_ent controls[VMSIG_MAX_CONTROLS]; int ncontrols; core_slot** slots; /* all allocated slots (for free) */ int nslots; int cap_slots; uint32_t epoch[64]; /* per-endpoint VM session epoch */ core_memctx_cell memctx[64]; /* per-endpoint retained context */ core_lease_cell lease[64][VMSIG_LEASE_CLASSES]; /* lease per (endpoint, class) */ vmsig_arb_policy arb_cb; /* preemption policy (NULL=default) */ void* arb_ud; void (*audit_cb)(void* ud, const vmsig_audit* a); void* audit_ud; }; /* Emit an audit record (no-op if no callback is set). Defined in core.c. */ void core_audit(vmsig_core* c, const vmsig_audit* a); /* Register an fd in epoll + create a slot (see core.c). */ core_slot* core_register_fd(vmsig_core* c, int fd, uint32_t epoll_events, slot_role role); /* Register an arbitrary fd source with a callback (e.g. a socket listen-fd). * The callback is called on the loop thread when the fd is ready. on_free (may be NULL) * is called at vmsig_core_free to clean up the source's resource. 0/-1. */ int core_add_source(vmsig_core* c, int fd, void (*cb)(void* user, uint32_t events), void* user, void (*on_free)(void* user)); /* Request detaching a control by id (deferred reap after the batch: epoll DEL, * close fd, ops->close). Safe to call from the control's own on_readable. */ void core_request_drop(vmsig_core* c, int ctl_id); /* emit hooks handed to adapters (UP) and controls (DOWN). Defined in loop.c. */ int core_emit_up (void* token, vmsig_event* ev); int core_emit_down(void* token, vmsig_event* ev); /* ===== Address-space context (MEMCTX seam; retained context) ===== */ /* Context registration hooks (handed to the adapter in vmsig_emit; defined in core.c). */ int core_register_memctx (void* token, const vmsig_memctx_reg* reg); void core_unregister_memctx(void* token, uint32_t endpoint); /* Multicast MEMCTX to qualified subscribers + mark the retain cell valid * (from pump_up on the VMSIG_EV_MEMCTX trigger; defined in loop.c). */ void core_memctx_route(vmsig_core* c, const vmsig_event* trigger); /* Replay retained MEMCTX to a single (late) subscriber (from vmsig_core_add_control; * defined in loop.c). */ void core_memctx_replay(vmsig_core* c, int ctl_id); /* Bump the endpoint's epoch on a destructive lifecycle transition: epoch++, invalidate * the retain cell, emit MEMCTX_INVALIDATED, request re-bootstrap from the adapter. * Observed by the core in pump_up on UP VM_LIFECYCLE (defined in loop.c). */ void core_epoch_bump(vmsig_core* c, uint32_t endpoint); /* ===== Lease layer (defined in loop.c) ===== */ /* Intercept CMD_ACQUIRE/RELEASE/LEASE_STATUS (synchronously from core_emit_down, not in ctx). */ void core_lease_acquire(vmsig_core* c, int ctl_id, const vmsig_event* ev); void core_lease_release(vmsig_core* c, int ctl_id, const vmsig_event* ev); void core_lease_status (vmsig_core* c, int ctl_id, const vmsig_event* ev); /* Reclaim the lease of a dead control (from core_reap, BEFORE e->active=0). */ void core_lease_reap_control(vmsig_core* c, int ctl_id); /* Wake the loop (eventfd nudge). Defined in loop.c. */ void core_wake(vmsig_core* c); #endif /* VMSIG_CORE_INTERNAL_H */