Phase C: distributed messaging capsule + idle-loop pump

Extract the messaging vocabulary (arenas, MSG-*/CH-*/MBR-* words) out of
capsules/hermes/init.4th into a new shared capsules/common/messaging.4th
that Hermes and Artemis each load at birth, giving every VM its own
private MSG-ARENA/CH-ARENA instead of only Hermes having one. Hermes
stays the owner of the one real, canonical COMMON-CH; Artemis subscribes
into it via VM-EXEC at her own birth, and Hermes proactively subscribes
Hera (idx 0) since Hera always exists first.

Hera does NOT get her own copy: register_child_vm_words()'s own doc
comment explains why the STADIUM-* primitives common:messaging.4th
depends on are deliberately never registered in her dictionary (keeps
her dict_hash off item 4.1's baseline). Confirmed live by loading it
into her dictionary anyway first -- every colon-definition referencing
an unregistered Stadium primitive was silently dropped (MSG-HEAT@/!,
CH-HEAT@/!, MSG-COOL-ALL, MSG-TICK all missing after boot). Reverted
that path; she orchestrates via BIRTH/VM-EXEC/VM-CALL instead.

Added capsule_vm_registry_get_by_index() (capsule_birth.c/.h) for
registry enumeration by birth-order position, and a pump in repl.c's
existing idle hook that walks every live VM once per idle beat and
VM-EXECs MSG-TICK into each one except Hera's own entry.

Verified clean (no UNKNOWN WORD / VM-EXEC errors after birth) on all
three architectures.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ZGkimpfyh63EZyRkNbkPD
This commit is contained in:
Robert Allan James
2026-08-28 13:02:23 -04:00
co-authored by Claude Sonnet 5
parent 0ec91b517a
commit 21bca315ff
16 changed files with 56059 additions and 550 deletions
+92 -91
View File
@@ -1,5 +1,5 @@
# Capsule Block Manifest — Auto-generated
<!-- Generated by mkcapsule --manifest 2026-08-28T13:36:29Z -->
<!-- Generated by mkcapsule --manifest 2026-08-28T17:01:08Z -->
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
<!-- Hand-written justifications and immutability notes live -->
<!-- in MANIFEST.md alongside this auto-generated index. -->
@@ -9,13 +9,14 @@
| Capsule | Blocks claimed | xxHash64 | Signed |
|---------|----------------|----------|--------|
| `ACL.4th` | 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4015 | `0xd781d22148ff171d` | yes |
| `artemis:init.4th` | 4110, 4111, 4112, 4113, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4131, 4132, 4133, 4134, 4135, 4136, 4137, 4138, 4139, 4140, 4141, 4160, 4161, 4162, 4163, 4164, 4165, 4166, 4167, 4168, 4169, 4170, 4171, 4172, 4173, 4174, 4177, 4178, 4179, 4180, 4181, 4182, 4851, 4852, 4853 | `0x8ecaf0453f02df27` | yes |
| `artemis:init.4th` | 4110, 4111, 4112, 4113, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4131, 4132, 4133, 4134, 4135, 4136, 4137, 4138, 4139, 4140, 4141, 4160, 4161, 4162, 4163, 4164, 4165, 4166, 4167, 4168, 4169, 4170, 4171, 4172, 4173, 4174, 4177, 4178, 4179, 4180, 4181, 4182, 4851, 4852, 4853, 4854 | `0xfe6e570467368153` | yes |
| `common:messaging.4th` | 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010, 5011, 5012, 5013, 5014, 5015, 5016, 5017, 5018, 5019, 5020, 5021, 5022, 5023, 5024, 5025, 5026, 5027, 5028, 5029, 5030, 5031, 5032, 5033, 5034, 5035, 5036, 5037 | `0x3eb5408bc357d1de` | yes |
| `common:msg.4th` | 4055 | `0x850a0382344ea6c4` | yes |
| `doe-campaign.4th` | 4060, 4061, 4062, 4063, 4064, 4065 | `0x3d4549142d91ec20` | yes |
| `doe.4th` | 2100, 2101, 2102, 2103, 2104, 2105, 2106, 2107 | `0xf154616d248e861f` | yes |
| `fabric.4th` | 4900, 4901, 4902, 4903, 4904, 4905, 4906, 4907, 4908, 4909, 4910, 4911, 4912, 4913, 4914, 4915, 4916, 4917, 4918, 4919, 4920, 4921, 4922, 4923, 4924, 5000, 5001, 5002 | `0x9b1d061339cea98d` | yes |
| `font.4th` | 4925, 4926, 4927, 4928, 4929, 4930, 4931, 4932, 4933, 4934, 4935, 4936, 4937, 4938, 4939, 4940, 4941, 4942, 4943, 4944, 4945, 4946, 4947, 4948, 4949, 4950, 4951, 4952, 4953, 4954, 4955, 4956, 4957, 4958, 4959, 4960, 4961, 4962, 4963, 4964, 4965, 4966, 4967, 4968, 4969, 4970, 4971, 4972, 4973, 4974, 4975, 4976, 4977, 4978, 4979, 4980, 4981, 4982, 4983, 4984, 4985 | `0x720792b4fc758156` | yes |
| `hermes:init.4th` | 4100, 4101, 4102, 4103, 4104, 4105, 4106, 4107, 4108, 4109, 4114, 4115, 4116, 4117, 4118, 4119, 4120, 4121, 4142, 4143, 4144, 4145, 4146, 4147, 4148, 4149, 4150, 4151, 4152, 4153, 4154, 4155, 4156, 4157, 4158, 4159, 4175, 4176, 5116 | `0xc4f09ac30715b659` | yes |
| `hermes:init.4th` | 4153, 4855, 5116 | `0x9d6119b69d4113af` | yes |
| `init-0.4th` | 2200, 2201 | `0xd0a9550baf786bb3` | yes |
| `init-1.4th` | 4406, 4415, 4425, 4435 | `0x63e251adb0a03613` | yes |
| `init-2.4th` | 4506, 4515, 4525, 4535, 4545 | `0xf113b3d0bcccae47` | yes |
@@ -114,89 +115,52 @@
| 4063 | `doe-campaign.4th` | `0x3d4549142d91ec20` | ok |
| 4064 | `doe-campaign.4th` | `0x3d4549142d91ec20` | ok |
| 4065 | `doe-campaign.4th` | `0x3d4549142d91ec20` | ok |
| 4100 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4101 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4102 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4103 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4104 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4105 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4106 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4107 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4108 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4109 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4110 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4111 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4112 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4113 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4114 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4115 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4116 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4117 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4118 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4119 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4120 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4121 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4122 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4123 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4124 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4125 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4126 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4127 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4128 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4129 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4130 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4131 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4132 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4133 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4134 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4135 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4136 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4137 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4138 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4139 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4140 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4141 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4142 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4143 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4144 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4145 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4146 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4147 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4148 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4149 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4150 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4151 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4152 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4153 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4154 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4155 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4156 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4157 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4158 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4159 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4160 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4161 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4162 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4163 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4164 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4165 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4166 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4167 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4168 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4169 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4170 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4171 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4172 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4173 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4174 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4175 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4176 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 4177 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4178 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4179 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4180 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4181 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4182 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4110 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4111 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4112 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4113 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4122 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4123 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4124 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4125 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4126 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4127 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4128 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4129 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4130 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4131 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4132 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4133 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4134 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4135 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4136 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4137 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4138 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4139 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4140 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4141 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4153 | `hermes:init.4th` | `0x9d6119b69d4113af` | ok |
| 4160 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4161 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4162 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4163 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4164 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4165 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4166 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4167 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4168 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4169 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4170 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4171 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4172 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4173 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4174 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4177 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4178 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4179 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4180 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4181 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4182 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4200 | `user-font-demo.4th` | `0xce1fd7d1b581a56d` | ok |
| 4201 | `user-font-demo.4th` | `0xce1fd7d1b581a56d` | ok |
| 4202 | `user-font-demo.4th` | `0xce1fd7d1b581a56d` | ok |
@@ -236,9 +200,11 @@
| 4840 | `init-l8-transition.4th` | `0xbcc1a81976f0a4c9` | ok |
| 4841 | `init-l8-transition.4th` | `0xbcc1a81976f0a4c9` | ok |
| 4842 | `init-l8-transition.4th` | `0xbcc1a81976f0a4c9` | ok |
| 4851 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4852 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4853 | `artemis:init.4th` | `0x8ecaf0453f02df27` | ok |
| 4851 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4852 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4853 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4854 | `artemis:init.4th` | `0xfe6e570467368153` | ok |
| 4855 | `hermes:init.4th` | `0x9d6119b69d4113af` | ok |
| 4900 | `fabric.4th` | `0x9b1d061339cea98d` | ok |
| 4901 | `fabric.4th` | `0x9b1d061339cea98d` | ok |
| 4902 | `fabric.4th` | `0x9b1d061339cea98d` | ok |
@@ -328,6 +294,41 @@
| 5000 | `fabric.4th` | `0x9b1d061339cea98d` | ok |
| 5001 | `fabric.4th` | `0x9b1d061339cea98d` | ok |
| 5002 | `fabric.4th` | `0x9b1d061339cea98d` | ok |
| 5003 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5004 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5005 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5006 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5007 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5008 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5009 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5010 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5011 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5012 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5013 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5014 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5015 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5016 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5017 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5018 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5019 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5020 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5021 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5022 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5023 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5024 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5025 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5026 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5027 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5028 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5029 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5030 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5031 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5032 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5033 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5034 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5035 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5036 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5037 | `common:messaging.4th` | `0x3eb5408bc357d1de` | ok |
| 5100 | `turtle.4th` | `0x4d470418ca543365` | ok |
| 5101 | `turtle.4th` | `0x4d470418ca543365` | ok |
| 5102 | `turtle.4th` | `0x4d470418ca543365` | ok |
@@ -344,11 +345,11 @@
| 5113 | `sdk.4th` | `0x008fdbbb62c94a3a` | ok |
| 5114 | `sdk.4th` | `0x008fdbbb62c94a3a` | ok |
| 5115 | `sdk.4th` | `0x008fdbbb62c94a3a` | ok |
| 5116 | `hermes:init.4th` | `0xc4f09ac30715b659` | ok |
| 5116 | `hermes:init.4th` | `0x9d6119b69d4113af` | ok |
## Conflicts
None.
---
*31 capsule(s) scanned. Re-run `mkcapsule --manifest <dir>` to refresh.*
*32 capsule(s) scanned. Re-run `mkcapsule --manifest <dir>` to refresh.*
+7
View File
@@ -491,4 +491,11 @@ Block 4853
( D.7: CD-INIT ran only via the old self-test; birth needs it. )
CD-INIT
S" lib.4th" EXEC
Block 4854
( Phase C 2026-08-28: own messaging vocab + subscribe into )
( Hermes's canonical COMMON-CH (idx 2 = Artemis, VM-NAMES- )
( INIT). Hermes always exists by Artemis's birth. )
S" common:messaging.4th" EXEC
MSG-CD-INIT
S" 2 COMMON-CH @ CH-ADD-MBR" S" Hermes" VM-EXEC
STARTUP-BANNER
+433
View File
@@ -0,0 +1,433 @@
Block 5003
( common:messaging.4th -- generic per-VM messaging vocab. )
1 CONSTANT SPAWN-EVENT
2 CONSTANT PAUSE-EVENT
3 CONSTANT RESUME-EVENT
4 CONSTANT KILL-EVENT
0 CONSTANT CH-NEGOTIATING
1 CONSTANT CH-OPEN
2 CONSTANT CH-CLOSING
9 CONSTANT MSG-CELLS
6 CONSTANT CH-CELLS
2 CONSTANT MBR-CELLS
32 CONSTANT MSG-MAX
16 CONSTANT CH-MAX
64 CONSTANT MBR-MAX
65208 CONSTANT Q-DECAY
255 CONSTANT MSG-DELIVERED
Block 5004
( StadiumBehaviour tags, match stadium.h's enum )
0 CONSTANT SB-MIGRATE
1 CONSTANT SB-DELIVER
2 CONSTANT SB-EXPIRE
3 CONSTANT SB-COOL
-1 CONSTANT STADIUM-NONE
( per-item admission heat for MSG-SEND/CH-ACCEPT. )
( Remaining reservoir after COMMON-CH's Q.1/3 floor, split )
( evenly across MSG-MAX messages + non-COMMON CH-MAX-1 slots. )
Q.1 Q.1 3 / - MSG-MAX CH-MAX 1- + / CONSTANT Q.SLOT
Block 5005
( arenas. heat/capacity via Stadium; MBR keeps its own )
( free list (not part of heat economy). )
CREATE MSG-ARENA MSG-MAX MSG-CELLS * CELLS ALLOT
CREATE CH-ARENA CH-MAX CH-CELLS * CELLS ALLOT
CREATE MBR-ARENA MBR-MAX MBR-CELLS * CELLS ALLOT
VARIABLE MSG-ALLOC-SLOT
VARIABLE CH-ALLOC-SLOT
VARIABLE MBR-FREE-HEAD
VARIABLE MSG-SEQ
VARIABLE CH-ACTIVE
VARIABLE COMMON-CH
Block 5006
( VM name routing table -- same fixed table every VM loads, )
( so IDX>NAME resolves identically everywhere. )
8 CONSTANT VM-MAX
CREATE VM-NAME-ADDRS VM-MAX CELLS ALLOT
CREATE VM-NAME-LENS VM-MAX CELLS ALLOT
: VM-NAME-REG ( addr u idx -- )
DUP VM-MAX >= IF DROP 2DROP EXIT THEN
>R R@ CELLS VM-NAME-LENS + !
R> CELLS VM-NAME-ADDRS + ! ;
: VM-NAMES-INIT ( -- )
S" Hera" 0 VM-NAME-REG
S" Hermes" 1 VM-NAME-REG
S" Artemis" 2 VM-NAME-REG ;
Block 5007
( INIT-FREE. stamps STADIUM-NONE into each slot's stadium- )
( cell field (msg off 5, ch off 3). Raw offsets: accessors )
( aren't defined yet in file order. )
: MSG-INIT-FREE ( -- )
MSG-MAX 0 DO
STADIUM-NONE I MSG-CELLS * CELLS MSG-ARENA + 5 CELLS + !
LOOP ;
: CH-INIT-FREE ( -- )
CH-MAX 0 DO
STADIUM-NONE I CH-CELLS * CELLS CH-ARENA + 3 CELLS + !
LOOP ;
Block 5008
( MBR-INIT-FREE (member free list, untouched) )
: MBR-INIT-FREE ( -- )
MBR-MAX 1- 0 DO
I MBR-CELLS * CELLS MBR-ARENA +
I 1+ MBR-CELLS * CELLS MBR-ARENA + SWAP !
LOOP
0 MBR-MAX 1- MBR-CELLS * CELLS MBR-ARENA + !
MBR-ARENA MBR-FREE-HEAD ! ;
Block 5009
( MSG-ALLOC: finds a free slot (TYPE=0) first, admits into )
( Stadium only once confirmed free (no leak). )
: MSG-FIND-FREE-SLOT ( -- addr|0 )
MSG-ARENA MSG-MAX 0 DO
DUP @ 0= IF UNLOOP EXIT THEN
MSG-CELLS CELLS +
LOOP DROP 0 ;
Block 5010
( MSG-ALLOC: pulls heat from reservoir first, admits )
( (identity=idx, heat=pulled), rolls back on refusal. )
: MSG-ALLOC ( heat -- addr|0 )
MSG-FIND-FREE-SLOT DUP 0= IF SWAP DROP EXIT THEN
MSG-ALLOC-SLOT !
STADIUM-RES-PULL
MSG-ALLOC-SLOT @ MSG-ARENA - MSG-CELLS CELLS /
SWAP DUP >R
SB-DELIVER STADIUM-ADMIT
DUP STADIUM-NONE = IF
DROP R> STADIUM-RES-PUSH 0 EXIT
THEN
R> DROP
MSG-ALLOC-SLOT @ MSG-CELLS CELLS 0 FILL
MSG-ALLOC-SLOT @ 5 CELLS + !
MSG-ALLOC-SLOT @ ;
Block 5011
( MSG-FREE-NODE: evict from Stadium, clear field )
: MSG-FREE-NODE ( addr -- )
DUP 5 CELLS + @ STADIUM-EVICT DROP
DUP 5 CELLS + STADIUM-NONE SWAP !
DROP ;
Block 5012
( MBR alloc/free (unchanged; not heat economy) )
: MBR-ALLOC ( -- addr|0 )
MBR-FREE-HEAD @ DUP 0= IF EXIT THEN
DUP @ MBR-FREE-HEAD !
DUP MBR-CELLS CELLS 0 FILL ;
: MBR-FREE-NODE ( addr -- )
MBR-FREE-HEAD @ OVER ! MBR-FREE-HEAD ! ;
Block 5013
( CH-FIND-FREE-SLOT. No TYPE field, so freeness is )
( stadium-cell = STADIUM-NONE. CH-ALLOC -> block 4176. )
: CH-FIND-FREE-SLOT ( -- addr|0 )
CH-ARENA CH-MAX 0 DO
DUP 3 CELLS + @ STADIUM-NONE = IF UNLOOP EXIT THEN
CH-CELLS CELLS +
LOOP DROP 0 ;
Block 5014
( CH-ALLOC: pulls heat from reservoir first, admits )
( (identity=idx, heat=pulled), rolls back on refusal. )
: CH-ALLOC ( heat -- addr|0 )
CH-FIND-FREE-SLOT DUP 0= IF SWAP DROP EXIT THEN
CH-ALLOC-SLOT !
STADIUM-RES-PULL
CH-ALLOC-SLOT @ CH-ARENA - CH-CELLS CELLS /
SWAP DUP >R
SB-COOL STADIUM-ADMIT
DUP STADIUM-NONE = IF
DROP R> STADIUM-RES-PUSH 0 EXIT
THEN
R> DROP
CH-ALLOC-SLOT @ CH-CELLS CELLS 0 FILL
CH-ALLOC-SLOT @ 3 CELLS + !
CH-ALLOC-SLOT @ ;
Block 5015
( CH-FREE-NODE: evict from Stadium, clear field )
: CH-FREE-NODE ( addr -- )
DUP 3 CELLS + @ STADIUM-EVICT DROP
DUP 3 CELLS + STADIUM-NONE SWAP !
DROP ;
Block 5016
( message field accessors )
: MSG-TYPE@ ( m -- n ) @ ;
: MSG-TYPE! ( n m -- ) ! ;
: MSG-FROM@ ( m -- n ) 1 CELLS + @ ;
: MSG-FROM! ( n m -- ) 1 CELLS + ! ;
: MSG-TO@ ( m -- n ) 2 CELLS + @ ;
: MSG-TO! ( n m -- ) 2 CELLS + ! ;
: MSG-PADDR@ ( m -- a ) 3 CELLS + @ ;
: MSG-PADDR! ( a m -- ) 3 CELLS + ! ;
: MSG-PLEN@ ( m -- u ) 4 CELLS + @ ;
: MSG-PLEN! ( u m -- ) 4 CELLS + ! ;
( offset 5 = Stadium cell idx. MSG-HEAT@/! -> 4154. )
: MSG-STADIUM-CELL@ ( m -- cell ) 5 CELLS + @ ;
: MSG-STADIUM-CELL! ( cell m -- ) 5 CELLS + ! ;
: MSG-SEQ@ ( m -- n ) 6 CELLS + @ ;
: MSG-SEQ! ( n m -- ) 6 CELLS + ! ;
Block 5017
( message accessors: CH@/CH! )
: MSG-CH@ ( m -- c ) 7 CELLS + @ ;
: MSG-CH! ( c m -- ) 7 CELLS + ! ;
: MSG-ORIG-TYPE@ ( m -- n ) 8 CELLS + @ ;
: MSG-ORIG-TYPE! ( n m -- ) 8 CELLS + ! ;
253 CONSTANT MSG-NACKED
Block 5018
( channel + member accessors )
: CH-ID@ ( c -- n ) @ ;
: CH-ID! ( n c -- ) ! ;
: CH-OWNER@ ( c -- n ) 1 CELLS + @ ;
: CH-OWNER! ( n c -- ) 1 CELLS + ! ;
: CH-STATE@ ( c -- n ) 2 CELLS + @ ;
: CH-STATE! ( n c -- ) 2 CELLS + ! ;
( offset 3 = Stadium cell index. CH-HEAT@/! -> 4154. )
: CH-STADIUM-CELL@ ( c -- cell ) 3 CELLS + @ ;
: CH-STADIUM-CELL! ( cell c -- ) 3 CELLS + ! ;
: CH-MBRS@ ( c -- a ) 4 CELLS + @ ;
: CH-MBRS! ( a c -- ) 4 CELLS + ! ;
: CH-NEXT@ ( c -- a ) 5 CELLS + @ ;
: CH-NEXT! ( a c -- ) 5 CELLS + ! ;
: MBR-NEXT@ ( m -- a ) @ ;
: MBR-VM@ ( m -- n ) 1 CELLS + @ ;
Block 5019
( composed MSG/CH-HEAT@/!, same names/stacks, bodies )
( routed via Stadium. Callers need no changes. )
: MSG-HEAT@ ( m -- q ) MSG-STADIUM-CELL@ STADIUM-HEAT@ ;
: MSG-HEAT! ( q m -- ) MSG-STADIUM-CELL@ STADIUM-HEAT! ;
: CH-HEAT@ ( c -- q ) CH-STADIUM-CELL@ STADIUM-HEAT@ ;
: CH-HEAT! ( q c -- ) CH-STADIUM-CELL@ STADIUM-HEAT! ;
Block 5020
( deliver )
VARIABLE MSG-LAST-MSG
: IDX>NAME ( idx -- addr u )
DUP VM-MAX >= IF DROP 0 0 EXIT THEN
DUP CELLS VM-NAME-ADDRS + @
SWAP CELLS VM-NAME-LENS + @ ;
: MSG-DELIVER ( m -- )
DUP MSG-LAST-MSG !
DUP MSG-PADDR@ OVER MSG-PLEN@
ROT MSG-TO@ IDX>NAME VM-EXEC ;
Block 5021
( MSG-SEND. heat -> MSG-ALLOC's admission directly )
( (zero-heat would lose eviction-fallback density )
( comparisons), not set afterward as before. )
: MSG-SEND ( type from to paddr plen ch -- )
Q.SLOT MSG-ALLOC DUP 0= IF 2DROP 2DROP 2DROP DROP EXIT THEN
>R
MSG-SEQ @ 1+ DUP MSG-SEQ ! R@ MSG-SEQ!
R@ MSG-CH!
R@ MSG-PLEN! R@ MSG-PADDR!
R@ MSG-TO! R@ MSG-FROM! DUP R@ MSG-TYPE! R@ MSG-ORIG-TYPE!
R> DROP ;
Block 5022
( MSG-COOL-ONE/ALL: linear decay per tick )
VARIABLE MSG-SCAN
: MSG-COOL-ONE ( m -- )
DUP MSG-HEAT@ Q-DECAY Q.* SWAP MSG-HEAT! ;
: MSG-COOL-ALL ( -- )
MSG-ARENA MSG-SCAN !
MSG-MAX 0 DO
MSG-SCAN @ MSG-HEAT@ 0 > IF
MSG-SCAN @ MSG-COOL-ONE
THEN
MSG-SCAN @ MSG-CELLS CELLS + MSG-SCAN !
LOOP ;
Block 5023
( MSG-TOTAL-HEAT )
: MSG-TOTAL-HEAT ( -- q48 )
0 MSG-ARENA MSG-SCAN !
MSG-MAX 0 DO
MSG-SCAN @ MSG-TYPE@ 0 <> IF
MSG-SCAN @ MSG-HEAT@ +
THEN
MSG-SCAN @ MSG-CELLS CELLS + MSG-SCAN !
LOOP ;
: MSG-REDELIVER-NACKED ( -- )
MSG-ARENA MSG-SCAN !
MSG-MAX 0 DO
MSG-SCAN @ MSG-TYPE@ MSG-NACKED = IF
MSG-SCAN @ MSG-ORIG-TYPE@ MSG-SCAN @ MSG-TYPE! THEN
MSG-SCAN @ MSG-CELLS CELLS + MSG-SCAN !
LOOP ;
Block 5024
( MSG-DELIVER-ALL )
: MSG-DELIVER-ALL ( -- )
MSG-ARENA MSG-SCAN !
MSG-MAX 0 DO
MSG-SCAN @ MSG-TYPE@ 0 <>
MSG-SCAN @ MSG-TYPE@ MSG-DELIVERED <> AND
MSG-SCAN @ MSG-TYPE@ MSG-NACKED <> AND IF
MSG-SCAN @ MSG-DELIVER
MSG-SCAN @ MSG-TYPE@ 0 <> IF
MSG-DELIVERED MSG-SCAN @ MSG-TYPE!
THEN
THEN
MSG-SCAN @ MSG-CELLS CELLS + MSG-SCAN !
LOOP ;
Block 5025
( message reaping )
( K reap only fires at heat=0: freed K contribution is 0. )
( Force-reap not yet implemented. If added: explicit )
( K redistribution will be required here. )
: MSG-REAP ( -- )
MSG-ARENA MSG-SCAN !
MSG-MAX 0 DO
MSG-SCAN @ MSG-HEAT@ 0 = IF
MSG-SCAN @ MSG-TYPE@ 0 <> IF
0 MSG-SCAN @ MSG-TYPE!
MSG-SCAN @ MSG-FREE-NODE
THEN
THEN
MSG-SCAN @ MSG-CELLS CELLS + MSG-SCAN !
LOOP ;
Block 5026
( channel cooling + heat aggregate )
VARIABLE CH-SCAN
: CH-COOL-ALL ( -- )
CH-ACTIVE @ CH-SCAN !
BEGIN CH-SCAN @ 0 <> WHILE
CH-SCAN @ CH-HEAT@ Q-DECAY Q.* CH-SCAN @ CH-HEAT!
CH-SCAN @ CH-NEXT@ CH-SCAN !
REPEAT ;
: CH-TOTAL-HEAT ( -- q48 )
0 CH-ACTIVE @ CH-SCAN !
BEGIN CH-SCAN @ 0 <> WHILE
CH-SCAN @ CH-HEAT@ +
CH-SCAN @ CH-NEXT@ CH-SCAN !
REPEAT ;
Block 5027
( channel reaping )
: CH-REAP-SAFE ( -- )
CH-ACTIVE @ CH-SCAN !
0 CH-ACTIVE !
BEGIN CH-SCAN @ 0 <> WHILE
CH-SCAN @ CH-NEXT@
CH-SCAN @ CH-HEAT@ 0 =
CH-SCAN @ COMMON-CH @ <> AND IF
CH-SCAN @ CH-FREE-NODE
ELSE
CH-ACTIVE @ CH-SCAN @ CH-NEXT!
CH-SCAN @ CH-ACTIVE !
THEN
CH-SCAN !
REPEAT ;
Block 5028
( COMMON + MSG-TICK (was HERMES-TICK -- generic now). )
( floor=Q.1/3. COMMON-CH VARIABLE is in block 4101. )
: COMMON-INIT ( -- )
Q.1 3 / CH-ALLOC DUP COMMON-CH !
0 OVER CH-ID! 0 OVER CH-OWNER!
CH-OPEN OVER CH-STATE!
0 OVER CH-MBRS!
CH-ACTIVE @ OVER CH-NEXT!
CH-ACTIVE ! ;
( floor-refresh is reservoir-constrained, may no-op under )
( pressure. )
: MSG-TICK ( -- )
MSG-DELIVER-ALL MSG-REDELIVER-NACKED
MSG-COOL-ALL MSG-REAP
CH-COOL-ALL CH-REAP-SAFE
Q.1 3 / COMMON-CH @ CH-HEAT! ;
Block 5029
( MSG-K (was HERMES-K -- generic now). WELCOME stays )
( behind in each VM's own init.4th. )
: MSG-K ( -- q48 )
MSG-TOTAL-HEAT CH-TOTAL-HEAT + STADIUM-RES@ +
STADIUM-WORD-HEAT + ;
Block 5030
( event compat interface. SPAWN/KILL notify-Hera is )
( automatic: see vm_physics_init/retire in mama_word_birth. )
: EVENT-EMIT ( type -- ) DROP ;
: EVENT-WAIT ( -- type )
MSG-ARENA MSG-SCAN !
MSG-MAX 0 DO
MSG-SCAN @ MSG-TYPE@ 0 <> IF
MSG-SCAN @ MSG-TYPE@ UNLOOP EXIT THEN
MSG-SCAN @ MSG-CELLS CELLS + MSG-SCAN !
LOOP 0 ;
: EVENT-DRAIN ( -- )
( no-op: MSG-REAP owns cleanup; drain breaks async ) ;
Block 5031
( channel negotiation: mint/request )
: CH-MINT-ID ( owner -- id )
MSG-SEQ @ 1+ DUP MSG-SEQ !
SWAP 32 LSHIFT OR ;
: CH-REQUEST ( type from to paddr plen -- )
COMMON-CH @ CH-STATE@ CH-OPEN = IF
COMMON-CH @ MSG-SEND
ELSE 2DROP 2DROP DROP THEN ;
Block 5032
( channel ops: accept confirm close )
: CH-ACCEPT ( -- ch|0 )
Q.SLOT CH-ALLOC DUP 0= IF EXIT THEN
1 CH-MINT-ID OVER CH-ID!
1 OVER CH-OWNER!
CH-NEGOTIATING OVER CH-STATE!
0 OVER CH-MBRS!
CH-ACTIVE @ OVER CH-NEXT!
DUP CH-ACTIVE ! ;
: CH-CONFIRM ( ch -- )
DUP CH-STATE@ CH-NEGOTIATING = IF CH-OPEN SWAP CH-STATE!
ELSE DROP THEN ;
: CH-CLOSE ( ch -- )
DUP COMMON-CH @ = IF DROP EXIT THEN
CH-CLOSING SWAP CH-STATE! ;
Block 5033
( MSG-CD-INIT (was CD-INIT -- renamed to avoid colliding )
( with Artemis's own unrelated block-subsystem CD-INIT). )
( common:msg.4th's HERMES-ACK/NACK indirection is retired: )
( every VM now has its own local MSG-ACK-LAST/NACK-LAST. )
: MSG-CD-INIT ( -- )
MSG-ARENA MSG-MAX MSG-CELLS * CELLS 0 FILL
CH-ARENA CH-MAX CH-CELLS * CELLS 0 FILL
MBR-ARENA MBR-MAX MBR-CELLS * CELLS 0 FILL
MSG-INIT-FREE
CH-INIT-FREE
MBR-INIT-FREE
0 MSG-SEQ !
0 MSG-LAST-MSG !
0 CH-ACTIVE !
COMMON-INIT
VM-NAMES-INIT ;
Block 5034
( ACK/NACK -- now purely local, no VM-EXEC indirection. )
: MSG-ACK-LAST ( -- )
MSG-LAST-MSG @ DUP 0= IF DROP EXIT THEN
0 OVER MSG-TYPE! MSG-FREE-NODE ;
: MSG-NACK-LAST ( -- )
MSG-LAST-MSG @ DUP 0= IF DROP EXIT THEN
DUP MSG-HEAT@ 2 / OVER MSG-HEAT!
MSG-NACKED SWAP MSG-TYPE! ;
Block 5035
( MSG-STATUS (was HERMES-STATUS -- generic now) )
: MSG-USED ( -- n )
0 MSG-ARENA MSG-SCAN !
MSG-MAX 0 DO
MSG-SCAN @ MSG-TYPE@ 0 <> IF 1+ THEN
MSG-SCAN @ MSG-CELLS CELLS + MSG-SCAN !
LOOP ;
: CH-USED ( -- n )
0 CH-ACTIVE @ CH-SCAN !
BEGIN CH-SCAN @ 0 <> WHILE
1+
CH-SCAN @ CH-NEXT@ CH-SCAN !
REPEAT ;
: MSG-STATUS ( -- )
MSG-USED . ." msgs " CH-USED . ." channels" CR ;
Block 5036
( member management )
: MBR-NEXT! ( a m -- ) ! ;
: MBR-VM! ( n m -- ) 1 CELLS + ! ;
: CH-ADD-MBR ( vm ch -- )
MBR-ALLOC DUP 0= IF DROP 2DROP EXIT THEN
ROT OVER MBR-VM!
OVER CH-MBRS@ OVER MBR-NEXT!
SWAP CH-MBRS! ;
Block 5037
( Phase 2: real multi-member broadcast )
VARIABLE BC-TYPE VARIABLE BC-FROM
VARIABLE BC-PADDR VARIABLE BC-PLEN
VARIABLE BC-CH VARIABLE BC-SCAN
: MSG-BROADCAST ( type from paddr plen ch -- )
BC-CH ! BC-PLEN ! BC-PADDR ! BC-FROM ! BC-TYPE !
BC-CH @ CH-MBRS@ BC-SCAN !
BEGIN BC-SCAN @ 0<> WHILE
BC-TYPE @ BC-FROM @ BC-SCAN @ MBR-VM@
BC-PADDR @ BC-PLEN @ BC-CH @ MSG-SEND
BC-SCAN @ MBR-NEXT@ BC-SCAN !
REPEAT ;
+14 -459
View File
@@ -1,467 +1,22 @@
Block 4100
( Hermes v1 — constants )
1 CONSTANT SPAWN-EVENT
2 CONSTANT PAUSE-EVENT
3 CONSTANT RESUME-EVENT
4 CONSTANT KILL-EVENT
0 CONSTANT CH-NEGOTIATING
1 CONSTANT CH-OPEN
2 CONSTANT CH-CLOSING
9 CONSTANT MSG-CELLS
6 CONSTANT CH-CELLS
2 CONSTANT MBR-CELLS
32 CONSTANT MSG-MAX
16 CONSTANT CH-MAX
64 CONSTANT MBR-MAX
65208 CONSTANT Q-DECAY
255 CONSTANT MSG-DELIVERED
Block 4155
( item 4.2 -- StadiumBehaviour tags, match stadium.h's enum )
0 CONSTANT SB-MIGRATE
1 CONSTANT SB-DELIVER
2 CONSTANT SB-EXPIRE
3 CONSTANT SB-COOL
-1 CONSTANT STADIUM-NONE
( item 4.2 -- per-item admission heat for MSG-SEND/CH-ACCEPT. )
( Remaining reservoir after COMMON-CH's Q.1/3 floor, split )
( evenly across MSG-MAX messages + non-COMMON CH-MAX-1 slots. )
Q.1 Q.1 3 / - MSG-MAX CH-MAX 1- + / CONSTANT Q.SLOT
Block 4101
( Hermes v1 -- arenas. item 4.2: heat/capacity via Stadium; )
( MBR keeps its own free list (not part of heat economy). )
CREATE MSG-ARENA MSG-MAX MSG-CELLS * CELLS ALLOT
CREATE CH-ARENA CH-MAX CH-CELLS * CELLS ALLOT
CREATE MBR-ARENA MBR-MAX MBR-CELLS * CELLS ALLOT
VARIABLE MSG-ALLOC-SLOT
VARIABLE CH-ALLOC-SLOT
VARIABLE MBR-FREE-HEAD
VARIABLE MSG-SEQ
VARIABLE CH-ACTIVE
VARIABLE COMMON-CH
Block 4142
( Hermes v1 — VM name routing table )
8 CONSTANT VM-MAX
CREATE VM-NAME-ADDRS VM-MAX CELLS ALLOT
CREATE VM-NAME-LENS VM-MAX CELLS ALLOT
: VM-NAME-REG ( addr u idx -- )
DUP VM-MAX >= IF DROP 2DROP EXIT THEN
>R R@ CELLS VM-NAME-LENS + !
R> CELLS VM-NAME-ADDRS + ! ;
: VM-NAMES-INIT ( -- )
S" Hera" 0 VM-NAME-REG
S" Hermes" 1 VM-NAME-REG
S" Artemis" 2 VM-NAME-REG ;
Block 4102
( Hermes v1 -- INIT-FREE. item 4.2: stamps STADIUM-NONE into )
( each slot's stadium-cell field (msg off 5, ch off 3). )
( Raw offsets: accessors aren't defined yet in file order. )
: MSG-INIT-FREE ( -- )
MSG-MAX 0 DO
STADIUM-NONE I MSG-CELLS * CELLS MSG-ARENA + 5 CELLS + !
LOOP ;
: CH-INIT-FREE ( -- )
CH-MAX 0 DO
STADIUM-NONE I CH-CELLS * CELLS CH-ARENA + 3 CELLS + !
LOOP ;
Block 4103
( Hermes v1 -- MBR-INIT-FREE (member free list, untouched) )
: MBR-INIT-FREE ( -- )
MBR-MAX 1- 0 DO
I MBR-CELLS * CELLS MBR-ARENA +
I 1+ MBR-CELLS * CELLS MBR-ARENA + SWAP !
LOOP
0 MBR-MAX 1- MBR-CELLS * CELLS MBR-ARENA + !
MBR-ARENA MBR-FREE-HEAD ! ;
Block 4156
( item 4.2 -- MSG-ALLOC: finds a free slot (TYPE=0) first, )
( admits into Stadium only once confirmed free (no leak). )
: MSG-FIND-FREE-SLOT ( -- addr|0 )
MSG-ARENA MSG-MAX 0 DO
DUP @ 0= IF UNLOOP EXIT THEN
MSG-CELLS CELLS +
LOOP DROP 0 ;
Block 4175
( item 4.2 -- MSG-ALLOC: pulls heat from reservoir first, )
( admits (identity=idx, heat=pulled), rolls back on refusal. )
: MSG-ALLOC ( heat -- addr|0 )
MSG-FIND-FREE-SLOT DUP 0= IF SWAP DROP EXIT THEN
MSG-ALLOC-SLOT !
STADIUM-RES-PULL
MSG-ALLOC-SLOT @ MSG-ARENA - MSG-CELLS CELLS /
SWAP DUP >R
SB-DELIVER STADIUM-ADMIT
DUP STADIUM-NONE = IF
DROP R> STADIUM-RES-PUSH 0 EXIT
THEN
R> DROP
MSG-ALLOC-SLOT @ MSG-CELLS CELLS 0 FILL
MSG-ALLOC-SLOT @ 5 CELLS + !
MSG-ALLOC-SLOT @ ;
Block 4157
( item 4.2 -- MSG-FREE-NODE: evict from Stadium, clear field )
: MSG-FREE-NODE ( addr -- )
DUP 5 CELLS + @ STADIUM-EVICT DROP
DUP 5 CELLS + STADIUM-NONE SWAP !
DROP ;
Block 4104
( Hermes v1 -- MBR alloc/free (unchanged; not heat economy) )
: MBR-ALLOC ( -- addr|0 )
MBR-FREE-HEAD @ DUP 0= IF EXIT THEN
DUP @ MBR-FREE-HEAD !
DUP MBR-CELLS CELLS 0 FILL ;
: MBR-FREE-NODE ( addr -- )
MBR-FREE-HEAD @ OVER ! MBR-FREE-HEAD ! ;
Block 4158
( item 4.2 -- CH-FIND-FREE-SLOT. No TYPE field, so freeness )
( is stadium-cell = STADIUM-NONE. CH-ALLOC -> block 4176. )
: CH-FIND-FREE-SLOT ( -- addr|0 )
CH-ARENA CH-MAX 0 DO
DUP 3 CELLS + @ STADIUM-NONE = IF UNLOOP EXIT THEN
CH-CELLS CELLS +
LOOP DROP 0 ;
Block 4176
( item 4.2 -- CH-ALLOC: pulls heat from reservoir first, )
( admits (identity=idx, heat=pulled), rolls back on refusal. )
: CH-ALLOC ( heat -- addr|0 )
CH-FIND-FREE-SLOT DUP 0= IF SWAP DROP EXIT THEN
CH-ALLOC-SLOT !
STADIUM-RES-PULL
CH-ALLOC-SLOT @ CH-ARENA - CH-CELLS CELLS /
SWAP DUP >R
SB-COOL STADIUM-ADMIT
DUP STADIUM-NONE = IF
DROP R> STADIUM-RES-PUSH 0 EXIT
THEN
R> DROP
CH-ALLOC-SLOT @ CH-CELLS CELLS 0 FILL
CH-ALLOC-SLOT @ 3 CELLS + !
CH-ALLOC-SLOT @ ;
Block 4159
( item 4.2 -- CH-FREE-NODE: evict from Stadium, clear field )
: CH-FREE-NODE ( addr -- )
DUP 3 CELLS + @ STADIUM-EVICT DROP
DUP 3 CELLS + STADIUM-NONE SWAP !
DROP ;
Block 4105
( Hermes v1 — message field accessors )
: MSG-TYPE@ ( m -- n ) @ ;
: MSG-TYPE! ( n m -- ) ! ;
: MSG-FROM@ ( m -- n ) 1 CELLS + @ ;
: MSG-FROM! ( n m -- ) 1 CELLS + ! ;
: MSG-TO@ ( m -- n ) 2 CELLS + @ ;
: MSG-TO! ( n m -- ) 2 CELLS + ! ;
: MSG-PADDR@ ( m -- a ) 3 CELLS + @ ;
: MSG-PADDR! ( a m -- ) 3 CELLS + ! ;
: MSG-PLEN@ ( m -- u ) 4 CELLS + @ ;
: MSG-PLEN! ( u m -- ) 4 CELLS + ! ;
( item 4.2: offset 5 = Stadium cell idx. MSG-HEAT@/! -> 4154. )
: MSG-STADIUM-CELL@ ( m -- cell ) 5 CELLS + @ ;
: MSG-STADIUM-CELL! ( cell m -- ) 5 CELLS + ! ;
: MSG-SEQ@ ( m -- n ) 6 CELLS + @ ;
: MSG-SEQ! ( n m -- ) 6 CELLS + ! ;
Block 4143
( Hermes v1 — message accessors: CH@/CH! )
: MSG-CH@ ( m -- c ) 7 CELLS + @ ;
: MSG-CH! ( c m -- ) 7 CELLS + ! ;
: MSG-ORIG-TYPE@ ( m -- n ) 8 CELLS + @ ;
: MSG-ORIG-TYPE! ( n m -- ) 8 CELLS + ! ;
253 CONSTANT MSG-NACKED
Block 4106
( Hermes v1 — channel + member accessors )
: CH-ID@ ( c -- n ) @ ;
: CH-ID! ( n c -- ) ! ;
: CH-OWNER@ ( c -- n ) 1 CELLS + @ ;
: CH-OWNER! ( n c -- ) 1 CELLS + ! ;
: CH-STATE@ ( c -- n ) 2 CELLS + @ ;
: CH-STATE! ( n c -- ) 2 CELLS + ! ;
( item 4.2: offset 3 = Stadium cell index. CH-HEAT@/! -> 4154. )
: CH-STADIUM-CELL@ ( c -- cell ) 3 CELLS + @ ;
: CH-STADIUM-CELL! ( cell c -- ) 3 CELLS + ! ;
: CH-MBRS@ ( c -- a ) 4 CELLS + @ ;
: CH-MBRS! ( a c -- ) 4 CELLS + ! ;
: CH-NEXT@ ( c -- a ) 5 CELLS + @ ;
: CH-NEXT! ( a c -- ) 5 CELLS + ! ;
: MBR-NEXT@ ( m -- a ) @ ;
: MBR-VM@ ( m -- n ) 1 CELLS + @ ;
Block 4154
( item 4.2 -- composed MSG/CH-HEAT@/!, same names/stacks, )
( new bodies routed via Stadium. Callers need no changes. )
: MSG-HEAT@ ( m -- q ) MSG-STADIUM-CELL@ STADIUM-HEAT@ ;
: MSG-HEAT! ( q m -- ) MSG-STADIUM-CELL@ STADIUM-HEAT! ;
: CH-HEAT@ ( c -- q ) CH-STADIUM-CELL@ STADIUM-HEAT@ ;
: CH-HEAT! ( q c -- ) CH-STADIUM-CELL@ STADIUM-HEAT! ;
Block 4107
( Hermes v1 — deliver )
VARIABLE MSG-LAST-MSG
: IDX>NAME ( idx -- addr u )
DUP VM-MAX >= IF DROP 0 0 EXIT THEN
DUP CELLS VM-NAME-ADDRS + @
SWAP CELLS VM-NAME-LENS + @ ;
: MSG-DELIVER ( m -- )
DUP MSG-LAST-MSG !
DUP MSG-PADDR@ OVER MSG-PLEN@
ROT MSG-TO@ IDX>NAME VM-EXEC ;
Block 4144
( Hermes v1 -- MSG-SEND. item 4.2: heat -> MSG-ALLOC's )
( admission directly (zero-heat would lose eviction-fallback )
( density comparisons), not set afterward as before. )
: MSG-SEND ( type from to paddr plen ch -- )
Q.SLOT MSG-ALLOC DUP 0= IF 2DROP 2DROP 2DROP DROP EXIT THEN
>R
MSG-SEQ @ 1+ DUP MSG-SEQ ! R@ MSG-SEQ!
R@ MSG-CH!
R@ MSG-PLEN! R@ MSG-PADDR!
R@ MSG-TO! R@ MSG-FROM! DUP R@ MSG-TYPE! R@ MSG-ORIG-TYPE!
R> DROP ;
Block 4108
( Hermes v1 — MSG-COOL-ONE/ALL: linear decay per tick )
VARIABLE MSG-SCAN
: MSG-COOL-ONE ( m -- )
DUP MSG-HEAT@ Q-DECAY Q.* SWAP MSG-HEAT! ;
: MSG-COOL-ALL ( -- )
MSG-ARENA MSG-SCAN !
MSG-MAX 0 DO
MSG-SCAN @ MSG-HEAT@ 0 > IF
MSG-SCAN @ MSG-COOL-ONE
THEN
MSG-SCAN @ MSG-CELLS CELLS + MSG-SCAN !
LOOP ;
Block 4145
( Hermes v1 — MSG-TOTAL-HEAT )
: MSG-TOTAL-HEAT ( -- q48 )
0 MSG-ARENA MSG-SCAN !
MSG-MAX 0 DO
MSG-SCAN @ MSG-TYPE@ 0 <> IF
MSG-SCAN @ MSG-HEAT@ +
THEN
MSG-SCAN @ MSG-CELLS CELLS + MSG-SCAN !
LOOP ;
: MSG-REDELIVER-NACKED ( -- )
MSG-ARENA MSG-SCAN !
MSG-MAX 0 DO
MSG-SCAN @ MSG-TYPE@ MSG-NACKED = IF
MSG-SCAN @ MSG-ORIG-TYPE@ MSG-SCAN @ MSG-TYPE! THEN
MSG-SCAN @ MSG-CELLS CELLS + MSG-SCAN !
LOOP ;
Block 4146
( Hermes v1 — MSG-DELIVER-ALL )
: MSG-DELIVER-ALL ( -- )
MSG-ARENA MSG-SCAN !
MSG-MAX 0 DO
MSG-SCAN @ MSG-TYPE@ 0 <>
MSG-SCAN @ MSG-TYPE@ MSG-DELIVERED <> AND
MSG-SCAN @ MSG-TYPE@ MSG-NACKED <> AND IF
MSG-SCAN @ MSG-DELIVER
MSG-SCAN @ MSG-TYPE@ 0 <> IF
MSG-DELIVERED MSG-SCAN @ MSG-TYPE!
THEN
THEN
MSG-SCAN @ MSG-CELLS CELLS + MSG-SCAN !
LOOP ;
Block 4109
( Hermes v1 — message reaping )
( K reap only fires at heat=0: freed K contribution is 0. )
( Force-reap not yet implemented. If added: explicit )
( K redistribution will be required here. )
: MSG-REAP ( -- )
MSG-ARENA MSG-SCAN !
MSG-MAX 0 DO
MSG-SCAN @ MSG-HEAT@ 0 = IF
MSG-SCAN @ MSG-TYPE@ 0 <> IF
0 MSG-SCAN @ MSG-TYPE!
MSG-SCAN @ MSG-FREE-NODE
THEN
THEN
MSG-SCAN @ MSG-CELLS CELLS + MSG-SCAN !
LOOP ;
Block 4114
( Hermes v1 — channel cooling + heat aggregate )
VARIABLE CH-SCAN
: CH-COOL-ALL ( -- )
CH-ACTIVE @ CH-SCAN !
BEGIN CH-SCAN @ 0 <> WHILE
CH-SCAN @ CH-HEAT@ Q-DECAY Q.* CH-SCAN @ CH-HEAT!
CH-SCAN @ CH-NEXT@ CH-SCAN !
REPEAT ;
: CH-TOTAL-HEAT ( -- q48 )
0 CH-ACTIVE @ CH-SCAN !
BEGIN CH-SCAN @ 0 <> WHILE
CH-SCAN @ CH-HEAT@ +
CH-SCAN @ CH-NEXT@ CH-SCAN !
REPEAT ;
Block 4115
( Hermes v1 — channel reaping )
: CH-REAP-SAFE ( -- )
CH-ACTIVE @ CH-SCAN !
0 CH-ACTIVE !
BEGIN CH-SCAN @ 0 <> WHILE
CH-SCAN @ CH-NEXT@
CH-SCAN @ CH-HEAT@ 0 =
CH-SCAN @ COMMON-CH @ <> AND IF
CH-SCAN @ CH-FREE-NODE
ELSE
CH-ACTIVE @ CH-SCAN @ CH-NEXT!
CH-SCAN @ CH-ACTIVE !
THEN
CH-SCAN !
REPEAT ;
Block 4116
( Hermes v1 -- COMMON + HERMES-TICK. floor=Q.1/3, VM-COUNT=3 )
( COMMON-CH VARIABLE now in block 4101; see CH-REAP-SAFE 4115 )
: COMMON-INIT ( -- )
Q.1 3 / CH-ALLOC DUP COMMON-CH !
0 OVER CH-ID! 0 OVER CH-OWNER!
CH-OPEN OVER CH-STATE!
0 OVER CH-MBRS!
CH-ACTIVE @ OVER CH-NEXT!
CH-ACTIVE ! ;
( item 4.2: floor-refresh now reservoir-constrained, may no-op )
( under pressure (was unconstrained write before). Watch log. )
: HERMES-TICK ( -- )
MSG-DELIVER-ALL MSG-REDELIVER-NACKED
MSG-COOL-ALL MSG-REAP
CH-COOL-ALL CH-REAP-SAFE
Q.1 3 / COMMON-CH @ CH-HEAT! ;
Block 4147
( Hermes v1 — HERMES-K + WELCOME )
( item 4.2: +STADIUM-WORD-HEAT so word patrons count -- 25.7 )
: HERMES-K ( -- q48 )
MSG-TOTAL-HEAT CH-TOTAL-HEAT + STADIUM-RES@ +
STADIUM-WORD-HEAT + ;
Block 4855
( Hermes v1 -- WELCOME. Generic messaging vocab moved to )
( common:messaging.4th, FABRIC-3.md Phase C 2026-08-28. )
: WELCOME ( -- ) LOG-INFO" Hermes: loaded" ;
WELCOME
Block 4117
( Hermes v1 — event compat interface )
( SPAWN/KILL notify-Hera is now automatic: see )
( vm_physics_init/retire in mama_word_birth/kill )
: EVENT-EMIT ( type -- ) DROP ;
: EVENT-WAIT ( -- type )
MSG-ARENA MSG-SCAN !
MSG-MAX 0 DO
MSG-SCAN @ MSG-TYPE@ 0 <> IF
MSG-SCAN @ MSG-TYPE@ UNLOOP EXIT THEN
MSG-SCAN @ MSG-CELLS CELLS + MSG-SCAN !
LOOP 0 ;
: EVENT-DRAIN ( -- )
( no-op: MSG-REAP owns cleanup; drain breaks async ) ;
Block 4118
( Hermes v1 -- readiness handshake, Phase 1 )
5 CONSTANT READY-EVENT
VARIABLE READY-COUNT
: NOTE-READY ( -- ) 1 READY-COUNT +! ;
: READY-ALL? ( -- flag ) READY-COUNT @ 3 >= ;
: ENQUEUE-READY ( from-idx -- )
READY-EVENT SWAP 1 S" NOTE-READY" COMMON-CH @ MSG-SEND ;
: HERMES-ANNOUNCE-READY ( -- ) 1 ENQUEUE-READY ;
: READY-ACK ( -- ) LOG-INFO" Hermes: ready-ack" ;
Block 4119
( Hermes v1 — channel negotiation: mint/request )
: CH-MINT-ID ( owner -- id )
MSG-SEQ @ 1+ DUP MSG-SEQ !
SWAP 32 LSHIFT OR ;
: CH-REQUEST ( type from to paddr plen -- )
COMMON-CH @ CH-STATE@ CH-OPEN = IF
COMMON-CH @ MSG-SEND
ELSE 2DROP 2DROP DROP THEN ;
Block 4148
( Hermes v1 — channel ops: accept confirm close )
: CH-ACCEPT ( -- ch|0 )
Q.SLOT CH-ALLOC DUP 0= IF EXIT THEN
1 CH-MINT-ID OVER CH-ID!
1 OVER CH-OWNER!
CH-NEGOTIATING OVER CH-STATE!
0 OVER CH-MBRS!
CH-ACTIVE @ OVER CH-NEXT!
DUP CH-ACTIVE ! ;
: CH-CONFIRM ( ch -- )
DUP CH-STATE@ CH-NEGOTIATING = IF CH-OPEN SWAP CH-STATE!
ELSE DROP THEN ;
: CH-CLOSE ( ch -- )
DUP COMMON-CH @ = IF DROP EXIT THEN
CH-CLOSING SWAP CH-STATE! ;
Block 4120
( Hermes v1 — CD-INIT )
: CD-INIT ( -- )
MSG-ARENA MSG-MAX MSG-CELLS * CELLS 0 FILL
CH-ARENA CH-MAX CH-CELLS * CELLS 0 FILL
MBR-ARENA MBR-MAX MBR-CELLS * CELLS 0 FILL
MSG-INIT-FREE
CH-INIT-FREE
MBR-INIT-FREE
0 MSG-SEQ !
0 MSG-LAST-MSG !
0 CH-ACTIVE !
COMMON-INIT
VM-NAMES-INIT
S" lib.4th" EXEC
S" common:msg.4th" EXEC
LOG-INFO" Hermes: ready" ;
Block 4121
( Hermes v1 — ACK/NACK server )
: MSG-ACK-LAST ( -- )
MSG-LAST-MSG @ DUP 0= IF DROP EXIT THEN
0 OVER MSG-TYPE! MSG-FREE-NODE ;
: MSG-NACK-LAST ( -- )
MSG-LAST-MSG @ DUP 0= IF DROP EXIT THEN
DUP MSG-HEAT@ 2 / OVER MSG-HEAT!
MSG-NACKED SWAP MSG-TYPE! ;
Block 4149
( Hermes v1 — HERMES-STATUS )
: MSG-USED ( -- n )
0 MSG-ARENA MSG-SCAN !
MSG-MAX 0 DO
MSG-SCAN @ MSG-TYPE@ 0 <> IF 1+ THEN
MSG-SCAN @ MSG-CELLS CELLS + MSG-SCAN !
LOOP ;
: CH-USED ( -- n )
0 CH-ACTIVE @ CH-SCAN !
BEGIN CH-SCAN @ 0 <> WHILE
1+
CH-SCAN @ CH-NEXT@ CH-SCAN !
REPEAT ;
: HERMES-STATUS ( -- )
MSG-USED . ." msgs " CH-USED . ." channels" CR ;
Block 4150
( Hermes v1 — member management )
: MBR-NEXT! ( a m -- ) ! ;
: MBR-VM! ( n m -- ) 1 CELLS + ! ;
: CH-ADD-MBR ( vm ch -- )
MBR-ALLOC DUP 0= IF DROP 2DROP EXIT THEN
ROT OVER MBR-VM!
OVER CH-MBRS@ OVER MBR-NEXT!
SWAP CH-MBRS! ;
: HERMES-MSG-TEST ( -- flag )
SPAWN-EVENT 1 0 0 0 COMMON-CH @ MSG-SEND
MSG-USED 0 > ;
Block 4151
( Hermes v1 -- Phase 2: real multi-member broadcast )
VARIABLE BC-TYPE VARIABLE BC-FROM
VARIABLE BC-PADDR VARIABLE BC-PLEN
VARIABLE BC-CH VARIABLE BC-SCAN
: MSG-BROADCAST ( type from paddr plen ch -- )
BC-CH ! BC-PLEN ! BC-PADDR ! BC-FROM ! BC-TYPE !
BC-CH @ CH-MBRS@ BC-SCAN !
BEGIN BC-SCAN @ 0<> WHILE
BC-TYPE @ BC-FROM @ BC-SCAN @ MBR-VM@
BC-PADDR @ BC-PLEN @ BC-CH @ MSG-SEND
BC-SCAN @ MBR-NEXT@ BC-SCAN !
REPEAT ;
Block 4152
( Hermes v1 -- Phase 2: COMMON-CH membership + test )
VARIABLE BCAST-GOT
: BCAST-RECV ( -- ) 1 BCAST-GOT +! ;
: REGISTER-COMMON-MEMBERS ( -- )
0 COMMON-CH @ CH-ADD-MBR
1 COMMON-CH @ CH-ADD-MBR
2 COMMON-CH @ CH-ADD-MBR ;
6 CONSTANT BCAST-EVENT
: SEND-BROADCAST-TEST ( -- )
BCAST-EVENT 1 S" BCAST-RECV" COMMON-CH @ MSG-BROADCAST ;
Block 4153
( LOAD-DOE: pulls in doe.4th's word-level DOE-WORK )
( workload, for doe-campaign.4th's remote VM-EXEC. )
: LOAD-DOE ( -- ) S" doe.4th" EXEC ;
Block 5116
( CD-INIT ran only via the old self-test; birth needs it now. )
CD-INIT
( Hermes owns the one real, canonical COMMON-CH. Every )
( other VM subscribes into it via VM-EXEC (see Artemis's )
( and Hera's own init.4th); Hera always exists first, so )
( Hermes adds her here rather than Hera subscribing to a )
( VM that doesn't exist yet at Hera's own birth. )
S" common:messaging.4th" EXEC
MSG-CD-INIT
S" lib.4th" EXEC
1 COMMON-CH @ CH-ADD-MBR
0 COMMON-CH @ CH-ADD-MBR
LOG-INFO" Hermes: ready"
STARTUP-BANNER
BIN
View File
Binary file not shown.
+13
View File
@@ -223,6 +223,19 @@ int capsule_vm_registry_get(VMUuid vm_id, VMRegistryEntry *out);
*/
uint32_t capsule_vm_registry_count(void);
/**
* capsule_vm_registry_get_by_index - Get registry entry by list position
* (birth order, stable within a boot session -- the registry is
* append-only). For enumeration (e.g. the idle-loop messaging pump,
* FABRIC-3.md Phase C, 2026-08-28), where no vm_id is known up front.
* Index range is [0, capsule_vm_registry_count()).
*
* @param index Zero-based position in birth order
* @param out Output: registry entry copy
* @return 0 on success, -1 if index is out of range
*/
int capsule_vm_registry_get_by_index(uint32_t index, VMRegistryEntry *out);
/**
* capsule_vm_find_by_name - Find VM registry entry by symbolic name
*
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+12
View File
@@ -199,6 +199,18 @@ uint32_t capsule_vm_registry_count(void) {
return vm_registry_count;
}
int capsule_vm_registry_get_by_index(uint32_t index, VMRegistryEntry *out) {
vm_node_t *node = vm_registry_head;
uint32_t i = 0;
if (!out) return -1;
while (node) {
if (i == index) { *out = node->entry; return 0; }
node = node->next;
i++;
}
return -1;
}
/* Live population, distinct from vm_registry_count above: vm_registry_count
* is monotonic (incremented on every vm_registry_alloc(), never decremented
* on death), so it counts every VM ever born, not the outer Stadium's
+14
View File
@@ -813,6 +813,20 @@ static void kernel_main_deep(BootInfo *boot_info) {
}
}
/* Phase C (2026-08-28): Hera does NOT get her own common:messaging.4th
* arena -- register_child_vm_words()'s own doc comment (mama_forth_
* words.c) explains why: the eight STADIUM-* FORTH primitives that
* word depends on (CH-HEAT@/!, MSG-HEAT@/! etc. all route through
* them) are deliberately never added to register_mama_forth_words(),
* to avoid moving Hera's dict_hash off item 4.1's baseline. Confirmed
* live: loading messaging.4th into Hera's own dictionary silently
* dropped every colon-definition that referenced one of those
* primitives (MSG-HEAT@/!, CH-HEAT@/!, MSG-COOL-ALL, MSG-TICK all
* missing after boot) -- not a timing bug, a real, pre-existing
* constraint. Hera orchestrates via BIRTH/VM-EXEC/VM-CALL directly
* instead; the idle-loop pump (repl.c) skips her own registry entry
* for the same reason. */
/* Hermes is now a permanent fleet-foundation VM, not self-test
* scaffolding -- FABRIC-3.md D.7 (birth-by-message-only, 2026-08-28):
* the Tripod legs (Hera/Hermes/Artemis) must be alive session-less so
+41
View File
@@ -37,6 +37,9 @@
#include "starkernel/xhci_driver.h"
#include "starkernel/blkio_usb.h"
#include "starkernel/homeblocks_sig.h"
#include "starkernel/capsule_birth.h"
#include "starkernel/capsule_run.h"
#include "starkernel/vm/bootstrap/sk_vm_bootstrap.h"
#include "block_subsystem.h"
#include "word_source/include/keyboard_words.h"
#include "word_source/include/block_words.h"
@@ -185,6 +188,44 @@ static void sk_repl_idle(VM *active_vm)
* write with no UPDATE, followed by an idle wait and an abrupt kill,
* did not survive a reboot until this fix. */
blk_vm_flush_all(active_vm);
/* FABRIC-3.md Phase C (2026-08-28): distributed messaging pump. Every
* live VM except Hera herself now owns its own MSG-ARENA/CH-ARENA and
* MSG-TICK word (see capsules/common/messaging.4th) instead of only
* Hermes having one -- "fully distributed, Hera pumps each VM's
* drain" was the confirmed design. Hera is excluded: she never loads
* common:messaging.4th (kernel_main.c's own comment at the Hermes-
* birth call site explains why -- the STADIUM-* primitives it needs
* are deliberately never registered in her own dictionary, to keep
* her dict_hash off item 4.1's baseline), so MSG-TICK is genuinely
* absent there, not just untried. She is the only VM with a
* persistent idle tick, so she walks the registry once per idle beat
* and VM-EXECs MSG-TICK into every OTHER live VM's own dictionary. */
{
VM *mama = (VM *)sk_get_mama_vm();
uint32_t count = capsule_vm_registry_count();
uint32_t i;
for (i = 0; i < count; i++) {
VMRegistryEntry ent;
if (capsule_vm_registry_get_by_index(i, &ent) != 0) continue;
if (ent.state != VM_STATE_LIVE) continue;
if (ent.vm_ptr == (void *)mama) continue;
static const char PFX[] = "S\" MSG-TICK\" S\" ";
static const char SFX[] = "\" VM-EXEC";
char cmd[128];
size_t p = 0;
size_t name_len = strlen(ent.name);
if (name_len > VM_NAME_MAX - 1u) name_len = VM_NAME_MAX - 1u;
memcpy(cmd + p, PFX, sizeof(PFX) - 1u); p += sizeof(PFX) - 1u;
memcpy(cmd + p, ent.name, name_len); p += name_len;
memcpy(cmd + p, SFX, sizeof(SFX) - 1u); p += sizeof(SFX) - 1u;
cmd[p] = '\0';
vm_interpret(mama, cmd);
}
}
}
/*===========================================================================