A dead VM leaves kernel-Hermes: KILL/reap drop it from every channel and release its pending mail (found starting M-B)
capsule_vm_kill() and capsule_vm_force_reap() never touched kernel-Hermes: a dead VM stayed a member of channel 0 and every channel it joined, its undelivered mail was never released, and anything published to it afterwards held heat forever. M-B's autonomous events would leak on every dead subscriber. Captain Bob: "Fix first, own commit." - sk_hermes_vm_departed(): unsubscribe from every channel, release + pop the pending queue (heat back to each funder, ledger exact), free the queue entry. Called from both kill and reap, with a HERMES departure line. Console evidence identical on amd64/aarch64/riscv64: wa with 2 pending -> "left 2 channel(s), released 2 pending", gone from .CHANNELS, PUBLISH to its channel delivers 0; acceptance ledger held=2048 (6144 without the release). Boot parity/dict_hash unchanged; acceptance passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
879d00dcf9
commit
b562e16ccf
@@ -40,6 +40,7 @@
|
||||
#include "starkernel/capsule_vm_switch_signal.h" /* FABRIC-3.md §XXVIII Stage 4 -- capsule_vm_force_reap() */
|
||||
#include "starkernel/vm/switch.h" /* FABRIC-3.8.md §3.5 -- sk_vm_parked_idle(), current VM */
|
||||
#include "starkernel/vm/kernel_hermes.h" /* FABRIC-3.6.md task 3.2 -- sk_hermes_channel_subscribe() */
|
||||
#include "freestanding/stdio.h" /* snprintf() -- the HERMES departure report */
|
||||
#include "word_source/include/framebuffer_words.h" /* FABRIC-3.6.md task 1.8 -- register_framebuffer_words() */
|
||||
#include "vm.h"
|
||||
#include "platform_alloc.h"
|
||||
@@ -340,6 +341,19 @@ void capsule_vm_set_pending_reap(VMUuid vm_id, int pending) {
|
||||
if (entry) entry->pending_reap = pending;
|
||||
}
|
||||
|
||||
/* A dead VM leaves kernel-Hermes: every channel, and its undelivered mail
|
||||
* released (heat back to each sender). Found at FABRIC-3.9.8 Stage M-B --
|
||||
* before this, KILL/reap left it a member everywhere, and anything
|
||||
* published to it afterwards held heat forever. */
|
||||
static void capsule_vm_hermes_depart(VMUuid vm_id, const char *name) {
|
||||
int left = 0, released = 0;
|
||||
char line[96];
|
||||
sk_hermes_vm_departed(vm_id, &left, &released);
|
||||
snprintf(line, sizeof line, "HERMES: %s departed -- left %d channel(s), released %d pending",
|
||||
(name && name[0]) ? name : "(unnamed)", left, released);
|
||||
console_println(line);
|
||||
}
|
||||
|
||||
void capsule_vm_force_reap(VMUuid vm_id) {
|
||||
VMRegistryEntry *entry = vm_find_entry_ptr(vm_id);
|
||||
if (!entry) return;
|
||||
@@ -378,6 +392,7 @@ void capsule_vm_force_reap(VMUuid vm_id) {
|
||||
* pending_reap -- a reaped VM is no longer a switch-signal
|
||||
* participant either way. */
|
||||
sk_vm_switch_signal_unregister(vm_id);
|
||||
capsule_vm_hermes_depart(vm_id, entry->name);
|
||||
|
||||
capsule_parity_log_kill(vm_id, entry->name);
|
||||
|
||||
@@ -528,6 +543,7 @@ int capsule_vm_kill(const char *name) {
|
||||
* an ordinary KILL left its slot behind (G6), to be walked by every
|
||||
* decision and never freed. No-op for a VM that never registered. */
|
||||
sk_vm_switch_signal_unregister(vm_id);
|
||||
capsule_vm_hermes_depart(vm_id, name);
|
||||
|
||||
entry->vm_ptr = (void *)0;
|
||||
entry->state = VM_STATE_DEAD;
|
||||
|
||||
Reference in New Issue
Block a user