Stage M-0: kernel-Hermes arena, pending queues and member lists grow on demand; Q_SLOT its own constant (FABRIC-3.9.0 §7.0, M-0/M-0b)
- The static sk_hermes_msgs[32] is replaced by a directory of fixed-size segments (SK_HERMES_ARENA_SEGMENT, growth granularity only). Messages never move -- callers, including the drain across vm_interpret_kind(), hold message pointers across later allocations, so copy-on-grow (as §7.0 first proposed) would dangle them. Each message carries its index; numbering unchanged. - Pending-queue rings and channel member lists heap-grown (doubling); member lists freed on destroy; reassembly scratch sized per call. SK_HERMES_MSG_MAX / _PENDING_MAX / _MEMBER_MAX are gone. - Q_SLOT = Q48_ONE / 32 as its own constant (M-0b), value unchanged. - Every grow failure is printed, logged at LOG_ERROR, counted (sk_hermes_grow_failures()) and refused whole; a send whose queue can't grow releases its message. Probe (reverted), identical on amd64/aarch64/riscv64: 70 messages in one queue (arena 32 -> 96), sender refused by its reservoir, 72 popped intact in order, 100 members; a live Hera drain on a full arena grew it mid-drain and released/popped the right message; each grow path's injected failure refused whole and counted. 3-ISA acceptance passes; boot parity, dict_hash set and the live ledger line byte-identical to before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
316be9fc4b
commit
d8358a3011
@@ -64,14 +64,22 @@
|
||||
#include "starkernel/q48_16.h" /* Q48_ONE */
|
||||
|
||||
/*
|
||||
* SK_HERMES_MSG_MAX / SK_HERMES_MEMBER_MAX - sizing. Mirrors
|
||||
* messaging.4th's own MSG-MAX (32) and MBR-MAX (64) as a starting point --
|
||||
* kernel-Hermes is a single central pool rather than N per-VM arenas, so
|
||||
* these may need revisiting once real traffic exists to size against. Not
|
||||
* a ruling, just where the FORTH precedent already was.
|
||||
* FABRIC-3.9.0.md §7.0 (Stage M-0): kernel-Hermes has no fixed counts any
|
||||
* more. SK_HERMES_MSG_MAX (32 messages system-wide), SK_HERMES_PENDING_MAX
|
||||
* (32 per queue) and SK_HERMES_MEMBER_MAX (64 per channel) are gone: the
|
||||
* message arena, each pending queue and each channel's member list grow on
|
||||
* demand from the kernel heap, and a grow that fails is logged, counted
|
||||
* (sk_hermes_grow_failures()) and refused whole.
|
||||
*
|
||||
* SK_HERMES_ARENA_SEGMENT - the arena's GROWTH GRANULARITY, not a limit.
|
||||
* The arena is a directory of fixed-size segments; running out adds a
|
||||
* segment. Messages never move once allocated -- callers hold
|
||||
* SkHermesMessage pointers across later allocations (the drain holds one
|
||||
* across interpreting a payload that may itself SEND), so a copy-on-grow
|
||||
* arena would leave them dangling. Only the segment directory is
|
||||
* allocate-copy-free, and nothing holds pointers into it.
|
||||
*/
|
||||
#define SK_HERMES_MSG_MAX 32
|
||||
#define SK_HERMES_MEMBER_MAX 64
|
||||
#define SK_HERMES_ARENA_SEGMENT 32
|
||||
|
||||
/* SK_HERMES_CHUNK_MAX_PAYLOAD - one block (1024 bytes, 64x16, SXLIV.1),
|
||||
* moved up here (was originally defined much further down, next to
|
||||
@@ -91,8 +99,15 @@
|
||||
* floor to protect. Deliberately simpler here rather than carrying the
|
||||
* old formula's now-unmotivated term forward: reservoir split evenly
|
||||
* across message slots only.
|
||||
*
|
||||
* FABRIC-3.9.0.md §7.0, ruling M-0b (Stage M-0): Q_SLOT is its own
|
||||
* constant now, 1/32 of a reservoir -- the same value as before, no longer
|
||||
* derived from the arena size (which no longer exists as a number). How
|
||||
* many messages a VM can have in flight is a heat question (its reservoir
|
||||
* over Q_SLOT), not a memory one.
|
||||
*/
|
||||
#define SK_HERMES_Q_SLOT ((uint64_t)Q48_ONE / SK_HERMES_MSG_MAX)
|
||||
#define SK_HERMES_Q_SLOT_DIVISOR 32u
|
||||
#define SK_HERMES_Q_SLOT ((uint64_t)Q48_ONE / SK_HERMES_Q_SLOT_DIVISOR)
|
||||
|
||||
/*
|
||||
* SkHermesMessage - one message slot, field-for-field mirror of
|
||||
@@ -169,6 +184,8 @@ typedef struct {
|
||||
* admission stamp (sk_vm_switch_signal_next_stamp())
|
||||
* -- how long the recipient has been waiting,
|
||||
* for the switch decision's tie-break */
|
||||
uint32_t index; /* Stage M-0: this message's arena index (its
|
||||
* identity -- queues hold indices, never pointers) */
|
||||
} SkHermesMessage;
|
||||
|
||||
/*
|
||||
@@ -176,12 +193,16 @@ typedef struct {
|
||||
* has joined, no per-member state beyond identity. Replaces the 28-word
|
||||
* channel abstraction; see this file's own top comment for why.
|
||||
*
|
||||
* @field members Member VM identities, valid for indices < count.
|
||||
* @field members Member VM identities, valid for indices < count. Stage
|
||||
* M-0: heap-grown on subscribe (was a fixed [64]); freed by
|
||||
* sk_hermes_channel_destroy().
|
||||
* @field count Number of valid entries in members[].
|
||||
* @field cap Allocated length of members[].
|
||||
*/
|
||||
typedef struct {
|
||||
VMUuid members[SK_HERMES_MEMBER_MAX];
|
||||
size_t count;
|
||||
VMUuid *members;
|
||||
size_t count;
|
||||
size_t cap;
|
||||
} SkHermesMembership;
|
||||
|
||||
/*
|
||||
@@ -302,7 +323,7 @@ uint64_t sk_hermes_audit_failure_count(void);
|
||||
|
||||
/*
|
||||
* Task 2.8 (item 28), SXXXVII.4: the scan that verifies the counters
|
||||
* themselves. DIAGNOSTIC ONLY -- O(SK_HERMES_MSG_MAX), never called from
|
||||
* themselves. DIAGNOSTIC ONLY -- O(arena capacity), never called from
|
||||
* alloc/release/decay.
|
||||
*
|
||||
* sk_hermes_scan_held - walks the message arena and sums the live Stadium
|
||||
@@ -385,8 +406,8 @@ int sk_hermes_channel_destroy(int channel_id);
|
||||
|
||||
/* sk_hermes_channel_subscribe - add vm_id to channel_id's membership.
|
||||
* Refuses (-1, no effect) if channel_id is invalid/not in use, vm_id is
|
||||
* already a member, or the channel's membership is already at
|
||||
* SK_HERMES_MEMBER_MAX. Idempotent in effect (a second call with the
|
||||
* already a member, or the member list can't grow (Stage M-0: logged and
|
||||
* counted, sk_hermes_grow_failures()). Idempotent in effect (a second call with the
|
||||
* same args refuses rather than duplicating), not in return value. */
|
||||
int sk_hermes_channel_subscribe(int channel_id, VMUuid vm_id);
|
||||
|
||||
@@ -506,12 +527,17 @@ int sk_hermes_send_one(VMUuid from, VMUuid to, uint32_t type, uint32_t channel_i
|
||||
int sk_hermes_publish(VMUuid from, int channel_id, uint32_t type,
|
||||
void *payload_addr, uint32_t payload_len);
|
||||
|
||||
/* SK_HERMES_PENDING_MAX - per-subscriber pending-queue depth. The global
|
||||
* message arena (SK_HERMES_MSG_MAX) is the real ceiling on how many
|
||||
* messages can ever be in flight system-wide, so sizing each VM's own
|
||||
* queue to that same bound is a safe, simple upper limit rather than a
|
||||
* new number to justify. */
|
||||
#define SK_HERMES_PENDING_MAX SK_HERMES_MSG_MAX
|
||||
/* Stage M-0: each subscriber's pending queue grows on demand (was a fixed
|
||||
* SK_HERMES_PENDING_MAX = 32). A queue that can't grow refuses the send,
|
||||
* which rolls the message back (released, ledger exact). */
|
||||
|
||||
/* sk_hermes_grow_failures - arena, queue, member-list and reassembly-scratch
|
||||
* grows that failed (each logged at LOG_ERROR and refused whole). */
|
||||
uint64_t sk_hermes_grow_failures(void);
|
||||
|
||||
/* sk_hermes_arena_capacity - messages the arena can currently hold without
|
||||
* growing (diagnostic; grows in SK_HERMES_ARENA_SEGMENT steps). */
|
||||
size_t sk_hermes_arena_capacity(void);
|
||||
|
||||
/* sk_hermes_pending_count - number of messages currently queued for
|
||||
* vm_id (0 if vm_id has no queue yet -- never having received a message
|
||||
@@ -664,9 +690,9 @@ uint32_t sk_hermes_chunk_count(uint32_t len);
|
||||
* seq order regardless of the order chunks[] itself is passed in.
|
||||
*
|
||||
* Refuses (-1, *out_len untouched, no partial copy ever lands in
|
||||
* out_buf) if: n_chunks is 0 or exceeds SK_HERMES_MSG_MAX (the system-
|
||||
* wide message arena size -- chunking can never need more chunk-carrier
|
||||
* messages than the whole arena holds); any chunk is NULL, has no
|
||||
* out_buf) if: n_chunks is 0; its per-call seq scratch can't be allocated
|
||||
* (Stage M-0: was a fixed [SK_HERMES_MSG_MAX] array; now sized to n_chunks,
|
||||
* a failure logged and counted); any chunk is NULL, has no
|
||||
* payload, or its payload is shorter than sizeof(SkHermesChunkHeader);
|
||||
* the chunks' msg_ids disagree; seq values are not exactly
|
||||
* {0..n_chunks-1} (a duplicate or a gap); is_last is not set on exactly
|
||||
|
||||
Reference in New Issue
Block a user