Working state — a note taken while the work happens, not a specification. The system as it is meant to be is in Architecture.
Cross-actor shared-state audit — ƿit runtime C
Worktree: /Users/johnalanbrook/Documents/work/cell/.claude/worktrees/agitated-dubinsky-a3501e
HEAD: c13443301 (branch claude/module-export-link-review-9f8813, off dev)
Method: pure code reading. No build, no seed, no tests. Nothing edited.
Precedent that motivated the audit: the image_lock per-call scan, fixed 2026-08-04
(plans/archive/night-2026-08-04/seed-speed.md §“Image-pin lock fix”).
Classification used throughout:
- (a) immutable after init — read-only, no contention possible
- (b) mutable but cold path — control plane, actor start/stop, compile, load
- (c) mutable on a hot path — per turn / per message / per call / per allocation
0. Executive answer to the three questions John actually asked
Do actors contend on shared mach pools during execution? No. Post-fix the per-call gate is one
memory_order_acquireload ofMachImageView.pin_owner(pit_internal.h:461-466) with no slow path at all. Everything else an executing image touches is read-only: the mapped bytes, the section table cached in the view, the shape rows, the stone constants. I enumerated every shared-write candidate — PGO counters,PitCodeRuntimeMeta,cpool_key_hashes, memoized text hashes, refcounts, stats — and every one is unreachable from the image lane or structurally closed (§3.4). Zero shared writes.pin_ownerdoes not even false-share with the control-plane refcounts. Pool granularity (per module / per executable / one serving many) changes only the mapping count and the pin/unpin traffic; it does not change the execution-time story at all.The contention that remains in the pool machinery is entirely control plane: 4
image_lockacquisitions per pool per actor start, each doing an O(n) linear scan, plus a full blake2b + STONE re-hash of the pool before the dedup that would have made it unnecessary (§3.2, §6.7).Is runtime-created text still interned/shared? No. John’s belief is correct and the code proves it.
Pit_NewStringLen,pretext_end,ppretext_end,Pit_ToString, concat — all allocate in the actor’s own heap viapit_alloc_string(ctx,…).pit_key_from_stringis documented and implemented as pure normalization with no allocation and no interning (source/pit_text_utf32.c:338-354). Thect_lockpool has exactly 7 live producers, all boot/registration/native-lane, listed in §2. The comment on the struct (“safe to reference from any actor”) is accurate but describes a much narrower population than its placement suggests.What else has the
image_lockshape? Ranked list in §6. The two real ones are the global actor registry + single global run queue on every message send (actors_mutexthenengine.lock), and the O(n) linear scan underimage_lockstill paid at every pin/unpin (a press pins ~149 images ⇒ quadratic control-plane work under one runtime-global mutex). Everything else is genuinely cold.
1. Complete inventory of runtime-global mutable state
1.1 struct PitRuntime — field by field (source/pit_internal.h:1265-1354)
| field | what it is | lock | written when | observers | class |
|---|---|---|---|---|---|
malloc_limit | soft cap | none | init | all | (a) |
identity | process-unique cache cookie, never 0/UINT32_MAX | none (source is _Atomic pit_runtime_identity_next, runtime.c:54) | once per Pit_NewRuntime* (runtime.c:1679) | all; read per dense-record alloc in the native lane | (a) |
buddy (BuddyAllocator) | the only source of GC heap blocks for every actor | buddy.lock — “protects all fields” (pit_internal.h:1253), taken inside buddy_alloc/buddy_free (runtime.c:1211,1313) | per GC heap block: actor heap create (runtime.c:1987), heap free (:2164), nursery grow/shrink (pit_gc_copy.c:857,2386,2895,2913), copy-space alloc (:1650,1654), compact dest block (pit_gc_compact.c:1646,1657) | every actor | (b) — but the hottest (b). See §6.3 |
regions_installed | did this rt install the process region table | none | init/teardown | — | (a) |
dynamic_region/static_region/owns_* (nan32) | fixed windows | none | init | all | (a) |
opaque_lock + opaque_values/opaque_next/opaque_capacity/opaque_count/opaque_free (nan32 only) | side table mapping a 32-bit handle → native void* for PITCLASS records | opaque_lock (runtime-global) | per Pit_SetOpaque; read per Pit_GetOpaque (pit_internal.h:1775-1788) | every actor holding any class record | (c) on nan32 only — see §6.5 |
ct_lock + ct_base/ct_free/ct_end/ct_pages/ct_hash/ct_array/ct_size/ct_count/ct_resize_threshold | the runtime-wide immutable text pool + its interning index | ct_lock | see §2 — boot keys, cfunc names, native-lane literals, and the arena bump for shapes/PitFunction/PitCode | every actor (read-only) | (b) writes; (a) for reads, except the unlocked ct_pages walk in is_ct_ptr — §6.4 |
builtin_key[7] | length,toJSON,source,flags,true,false,null resolved through the ct pool at init (runtime.c:194-212) | none needed | init only | all | (a) |
shape_count, shape_bytes | accounting for shape rows the Mach loader builds in constant memory | ct_lock (runtime.c:998-1004) | per pit_record_shape_new | $inspect.snapshot() | (b) — see §2.3 |
code_lock | guards pgo_sessions | — | — | — | — |
code_cache_count, code_cache_bytes | gravestone. Nothing writes them; tests assert exactly zero (comment pit_internal.h:1316-1323). Verified: no writer in tree. | code_lock | never | $inspect | (a) |
pgo_sessions, pgo_disabled_sites (atomic_uint), pgo_disabled_warned (atomic_bool) | dev-only PGO sessions, keyed by semantic graph + compiler salt; NULL in every ordinary runtime | code_lock for the list; hot counters lock-free | list mutated per PGO session open/close (mach_vm.c:746-835,1180-1200) | actors running instrumented code | (b) list / (c) counters when PGO is on — §3.4 |
cfunc_lock + cfunc_cache, cfunc_cache_count, cfunc_cache_bytes | runtime-wide cache of immortal PitFunction objects for C functions, keyed by (fnptr, name, arity, proto, magic) | cfunc_lock | per Pit_NewCFunction2 → per registered C function per actor start (runtime.c:2347-2399); linear list scan with strcmp under the lock | every actor receives the same PitValue | (b) — §4.3 |
image_lock + pinned_mach_images, pinned_mach_image_count, pinned_mach_image_capacity | exact ranges of provider-owned views pinned into this runtime | image_lock | pin/unpin, each an O(n) linear scan (registry.c:72-156) | GC + diagnostics | (b) — §6.2, still the biggest remaining lock |
mach_image_placements, mach_image_released, mach_image_teardown_depth | placement list + deferred-release list for teardown ordering | image_lock | placement create/detach, actor-heap teardown | — | (b) |
1.2 Process/file-scope mutable state (non-vendored, non-test)
source/runtime.c
:53PitClassID pit_class_id_alloc— non-static global, plain++at:2222. No lock, no atomic. Written whenever a native module registers an opaque class (Pit_NewClassID). → §5.1, a real bug.:54static _Atomic uint32_t pit_runtime_identity_next— fine, atomic, once per runtime.:73static PitRegionTable pit_region_table— process-global. Install-once under an_Atomic int installedCAS latch (:136-157); removed at teardown. (a) after install. nan64 reads it only for bookkeeping/diagnostics (pit_region_findhas zero non-test callers in tree). nan32 reads the derived window table on every pointer encode/decode.:83static PitNan32Windows pit_nan32_windows— derived mirror, written insidepit_regions_install. (a) after install, but read on every nan32 value encode/decode (:235-271). Read-only, so no contention.:84static _Atomic(PitRuntime *) pit_nan32_active_runtime— one runtime owns the nan32 opaque table. (a) after install.:2509static PitLogSink g_log_sink— process-once tee (web ring buffer).
source/scheduler.c
:43static timer_node *timer_heap— global timer min-heap, all mutations underengine.lock. (b), per timer arm/fire.:71/:72lane driver token:_Atomicsource +_Thread_localholder. Clean.:75-90static struct {...} engine— THE global: onelock, three condvars,q_head/q_tail[4],main_q_*,execution_lanes,shutting_down, worker threads. (c) — every enqueue (enqueue_actor_priority:2315-2345) and every dequeue takesengine.lock.:93static char *g_log_actor_id— malloc’d id of the logger actor. Read (system_log_active,is_log_actor) on every log and every traced turn;strdup/freed on logger register/teardown with no lock. → §5.2, a use-after-free shape.:96static int g_system_trace— control toggle, read per turn.:99_Thread_local PitContext *g_execution_ctx— TLS, per turn entry/exit. Correct.:181/:182boot-trace path + mirror flag — process-once.:846-848actors_mutex,actors(stb_ds string map),starting_actors— the actor registry. (c):scheduler_ref_actor(id)/get_actor(id)take this global mutex + do a string hash lookup on everysend_message(:4192-4245).:869watchers_mutex— the deliberate process-global leaf lock forstop_watchers. Its own comment (:850-868) says a reply-carrying send registers a watch, “so this path runs constantly rather than once per$couple” ⇒ (c).:3318and:5029static uint32_t global_timer_id— two independent counters, each++’d outsideengine.lock. → §5.3.:3217static int already_exiting— atexit guard, harmless.
source/registry.c (whole file read)
:20-23pit_static_extensions/pit_static_endowments(+counts) — install-once, header says “No thread safety: the static table is installed once during startup”. (a). Lookup is a linearstrcmpscan (:331-339) — O(n_extensions) peruse(), cold but O(n).:35/:36static atomic_flag pit_lease_lock+pit_actor_leases— process-global spin lock (while(atomic_flag_test_and_set), no pause/yield,:210-216) over a linked list walked withstrcmp. (b), rare. Noted as a latent priority-inversion on an oversubscribed box, not a current problem.:398static PitTickDrainEntry *pit_tick_drain_head— unsynchronized head-swap push (:400-408), never removed. → §5.4.
source/start_plan.c
:100-102static PitPlanImage plan_images[1024]+plan_image_count, guarded bystatic sys_mutex_t plan_images_lock. Daemon-lifetime scratch-image registry, slot 0 = boot cart, never evicted (this is thePLAN_IMAGE_MAX=256-shaped gotcha already in memory). (b).
source/cart_boot.c
:79static PitCartBoot g_cart_boot— mounted boot cartridge sections. Written once before any runtime exists. (a).
source/image_provider.c
:72-75fourstatic PitClassID(image_handle,image_pin,pool_binding,image_authorization) — lazily initialized through the unsynchronizedPit_NewClassID(:353-357). Inherits §5.1.
source/mach_pool.c
:1122/:1134/:1144three tri-state env levers (PIT_MACH_NO_FUSE,…NO_GUARD_FUSE,…NO_TEXT_GUARD_FUSE), lazily resolved. Racy but idempotent (getenv is stable) ⇒ benign. Consulted at load, never in dispatch.:2325static char effective[128]inPit_MachABIEffective— lazy, idempotent, benign.
source/mach_vm.c
:735static atomic_uint g_pgo_snapshot_generation— atomic, per snapshot. Fine.
source/pit.c
:24char g_shop_actor_id[65](non-static),:28static PitBootConfig g_boot_config,:29PitRuntime *g_runtime(non-static; also extern’d bycrash.c),:35static int g_cli_exit_code,:427static pit_trace_hook g_pit_trace_hook. All process-once at boot exceptg_cli_exit_code(written by the terminal actor). (a)/(b).g_runtimelazy init at:147-149is an unguarded check-then-set, but it runs before any second thread exists in every real path.
source/crash.c
:32_Thread_local volatile PitContext *g_crash_ctx— TLS, per turn. Correct.:36static char crash_log_path[PATH_MAX]— process-once.
source/press_value.c
:39static PitPressRep press_reps[]is non-const: rows’value_bitsare patched bypress_reps_ready()(:63-77) behind a fn-localstatic int state. Lazy, idempotent, benign — but it is a writable table.
GC files — all thread-local, zero shared state. pit_gc_copy.c (gc_ys_*, gc_from2_*, gc_minor_*, gc_from_frame_*) and pit_gc_compact.c (gcm_*: phase, mark bitmap, worklist, delta window, seen set) are __thread. The attribution globals gc_scan_container* (pit_gc_copy.c:915-919, mirrored pit_gc_compact.c:485-489) are explicitly TLS with a comment saying so because actor workers run concurrent GCs. This is exactly right and is the single best-isolated subsystem in the runtime.
Files with no file-scope mutable state at all: pit_module_internal.c, pit_text_utf32.c, pit_text_kim.c, pit_ring.c, pgo_profile.c, main.c, press_stubs.c, qbe_stubs.c, press_rep_*.c, buddy_debug.c, wildmatch.c.
1.3 Per-actor state, for contrast (all correct)
PitContext owns: its heap (heap_base/heap_free/heap_end/frame_free), nursery,
class_array (per-actor! runtime.c:2236,2256), letters, parks_head, signals_head,
rec_key_next, mutex (turn), msg_mutex (mailbox), and the _Atomic handshake fields
(state, refcount, turn_gen, pause_flag, debug_suspended, profile_*). Nothing
in an actor’s value graph is reachable from another actor’s value graph.
2. The interned-text question — VERDICT: John is right
2.1 What still allocates into the ct pool
Total live producers of rt_ct_alloc / pit_rt_ct_alloc / rt_intern_text_to_value:
| site | what | when | frequency |
|---|---|---|---|
runtime.c:207 (rt_init_builtin_keys) | the 7 builtin property-name keys | runtime init | 7 per process |
runtime.c:2351 (pit_new_cfunc_internal) | the name key of a C function | per C-function registration | bounded by #C functions in the binary |
runtime.c:2365 | the immortal PitFunction object for that C function | same | same |
runtime.c:999 (pit_record_shape_new) | one PitRecordShape row + its key rows | per native-lane record template prime | native lane only |
runtime.c:4234 (Pit_NewAtomString in the property-list installer) | property name from a PitCFunctionListEntry | per module registration | bounded |
mach_vm.c:2187,2199 | a PitCode wrapper | per image-code wrap | bounded by units |
qbe_helpers.c:438,481,753,2186 | native-lane literal keys, template keys, PitCode | native (QBE) lane only, cold-primed once | native lane only |
That is the entire list. greped across source/, platform/, packages/, internal/.
2.2 What explicitly does NOT intern (the important half)
Pit_NewStringLen(pit_text_utf32.c:588-639) →pit_alloc_string(ctx,…)→ actor heap, thenpretext_endstones it in place. Never touchesct_*.pretext_*(concat/append/text()) → actor heap.ppretext_end(parser) → actor heap.pit_key_from_string(pit_text_utf32.c:345-354) — the function everyobj[k]andPit_SetPropertyStrgoes through: identity for a non-empty text,PIT_KEY_emptyfor an empty one, zero allocation, zero interning. Its own comment says so and the body agrees.mach_pool.c:2114-2146carries the gravestone comment for the thing John remembers: the generation-time probe “used to build one throughpit_key_new, which permanently interned every string constant of every generated unit just to ask”. That interning is gone; the probe is now answered from the cpool entry type.
2.3 So what is shared, and what lock is on the read path
Shared, immortal, read-only after creation: the 7 builtin keys, C-function name
keys, C-function PitFunction objects, native-lane shape rows and their key rows.
All are objhdr_s (stone) and live in a runtime arena the GC refuses to move
(is_ct_ptr gate at pit_gc_copy.c:1175,1692).
The read path has no lock at all, and it does not need one:
pit_key_hash(pit_text_utf32.c:215-241) —chase()+get_text_hash. For a stone text the hash is memoized in the object (text->hash), computed once at creation. For a ct-pool text it is written at intern time underct_lock. No write on the read path.pit_key_equal(runtime.c:523-552) — pointer compare, then type compare, thenPitText_equal(amemcmpof packed words). Reads only the two texts.pit_mach_record_get_hashed/rec_find_slot_hashed(runtime.c:580+) — probes the actor’s own record table; the keys it compares against are actor-heap texts or image/ct stone texts. Read-only either way.
Therefore the profile leaves pit_key_equal (886 samples) and
pit_mach_record_get_hashed (529) from the post-fix sample in
plans/archive/night-2026-08-04/seed-speed.md are honest interpreter work, not shared-state
contention. Against Pit_CallRegisterVMFunction’s 14,509 they are ~6% and ~4% of the
interpreter. Nothing to fix there.
2.4 shape_count / shape_bytes
Shape rows are what pit_record_shape_new (runtime.c:954-1020) builds: a
PitMachPoolShapeRow (== PitRecordShape) plus contiguous 16-byte key rows, laid out
byte-identically to what an image carries, so a record cannot tell a decoded shape
from a mapped one — it holds a bare pointer and does two hops either way
(pit_internal.h:332-339).
Facts established:
- There is no shape table. Nothing looks a shape up; density comes from records
sharing one descriptor that the code object holds. The comment
(
pit_internal.h:1307-1312) is accurate. - Shapes are shared across actors: they are immortal, in constant memory, and a record in any actor may point at one. They are write-once.
shape_count/shape_bytesmove underct_lockwith the allocation, so they add zero lock acquisitions of their own.- Lock traffic: one
ct_lockacquisition per shape created, and shapes are created only fromqbe_helpers.c:759(native record-template priming, once per template per runtime) plus the C tests. In the mach lane, shapes come mapped from the pool and cost nothing.
3. The mach pool / image sharing model
3.1 Object graph — where each thing lives
| structure | defined | lives where | shared? | mutable when |
|---|---|---|---|---|
| the mapping (pool bytes) | — | sys_mem_map’d read-only file, or a resident window | shared by all actors | never (RO) |
MachImageView | pit_internal.h:363-389 | provider-owned runtime storage: embedded in a PitMachImagePlacement, or a caller’s own struct | shared | at open (fields), then only pin_owner |
PitMachImagePlacement | image_provider.c | runtime table rt->mach_image_placements (off GC heap) | shared | under image_lock: create, refcount, detach, deferred release |
PoolBinding | pit_internal.h:403-412 | inside a PitMachPoolBindingHandle record (actor-heap PITCLASS record, opaque ptr to malloc’d struct) | per-actor (the handle is non-transferable) | immutable for one image generation |
PitPinnedMachImageRange | pit_internal.h:414-419 | rt->pinned_mach_images[], pit_realloc_rt’d array | shared | pin/unpin under image_lock |
PitRecordShape rows | pit_internal.h:326-339 | inside the mapping (mapped units) or the ct arena (decoded units) | shared | write-once |
The load-bearing lifetime argument (verified against image_provider.c): a live
PoolBinding always holds its own pin — provider_binding_for_placement acquires a pin
before building the handle, and handle->active is never cleared for a binding class.
So binding->image (== &placement->view, runtime-owned storage, not mapping
storage) is safe to dereference wherever binding is, and
provider_detach_unused_locked cannot free the placement while pin_refs != 0.
One more fact that keeps the whole model sane: placements are deduplicated.
provider_adopt_mapping (image_provider.c:217-240) looks the candidate up by
(placement_id, artifact_hash, profile_hash, abi_hash, mapping_owned) before creating
one, and start_plan.c:290-294 names a placement by the byte range’s own address
("plan:%p:%llu"). So N actors starting the same pool get one placement, one view, and
one PitPinnedMachImageRange with pin_count == N. The registry’s size scales with
distinct pools, not with actors.
3.2 Lifecycle traffic under image_lock
source/registry.c is the whole of it and it is small:
pit_runtime_pin_mach_image(:72-126) — lock, linear scan ofpinned_mach_imagesfor this view; bumppin_countor append a new range (realloc doubling);pit_mach_image_publish_owner(image, rt)(release store ofrtintoview->pin_owner); unlock. O(n) per pin.pit_runtime_unpin_mach_image(:128-156) — lock, linear scan, decrement; at zero, publish ownerNULLand swap-remove the range; unlock. O(n) per unpin.pit_runtime_mach_image_pin_count(:158-171) — still locked, still a scan, but now only cold callers (C regressions,dbg_code_from_functionatruntime.c:10021).pit_runtime_contains_pinned_mach_pointer(:181-195) — locked scan. Reached only throughpit_ptr_is_live_value(pit_internal.h:2993-2996), whose only non-HEAP_CHECKcaller isruntime.c:10163(an inspect/aliasing answer). Not hot in release. Good — but note its header comment (pit_internal.h:433-436) says it “is used only by GC and diagnostics”. The GC does not call it. The comment overclaims; correct it.pit_runtime_dispose_mach_image_registry(:197-208) — teardown, asserts balance.
Frequency, counted exactly. Per pool window at actor start (start_plan.c:286-301
→ image_provider.c:945-1012): 4 image_lock acquisitions —
provider_adopt_mapping (:235, holding the lock across a linear scan of
mach_image_placements doing a strcmp + three 32-byte memcmps per entry),
pit_runtime_pin_mach_image (registry.c:79, linear scan of pinned_mach_images,
possibly pit_realloc_rt), provider_acquire_pin’s pin_refs++ (:265), and
provider_release_open (:278).
Per binding at actor stop: pit_runtime_images_teardown_begin (1, :190-195, from
Pit_FreeContext at runtime.c:2085), then per binding finalizer
pit_runtime_unpin_mach_image + pin_refs--/provider_detach_unused_locked (2 in the
common case, 3 when this is the last actor), then pit_runtime_images_teardown_end
(1, :197-208, at runtime.c:2173).
So lock traffic is O(actors × windows) even though the tables are O(pools). Loose per-module realization makes both numbers large at once: 149 images, each pin scanning up to 149 entries, all through one runtime-global mutex. It did not show in the post-fix profile because the per-call amplification is gone — but it is the same lock and the same scan, one order of magnitude down.
And the lock is not even the expensive part of actor start. provider_adopt_bytes
runs crypto_blake2b over the entire window (image_provider.c:878) and then
Pit_MachPoolOpen (:889-891) re-hashes every STONE text via
mach_pool_stone_text_section_valid (mach_pool.c:684) — and both happen before the
dedup lookup. Every actor starting an already-mapped pool therefore redoes O(pool
bytes) of hashing that the existing placement already proved. The file path
(provider_open, :484) additionally mmaps and munmaps per call around the dedup.
See §6.7.
3.3 Execution path, post-fix — what is READ
Per call into a PIT_FUNC_KIND_IMAGE function, the shared memory read is:
binding->runtime == ctx->rt— a plain load from the actor’s own malloc’d binding.pit_mach_image_pinned_by(binding->image, ctx->rt)(pit_internal.h:461-466) — oneatomic_load_explicit(memory_order_acquire)ofview->pin_owner, compared tort. (mach_vm.c:437-445.) There is no slow path at all —mach_binding_is_pinnedis three pointer-word compares plus one acquire load, and on failuremach_exec_from_function(:447-460) answers an invalid cursor. Verified: no conditional fallback topit_runtime_mach_image_pin_countexists. The only writers ofpin_ownerareregistry.c:92(existing entry, republish — idempotent),:123(new entry),:145(pin_counthit 0, publish NULL), all release stores underimage_lock. Release/acquire throughout; no relaxed anywhere in the pair.- The
MachImageViewfields it needs —sections[],value_row_count(cached at open precisely somach_exec_const_count, “the hottest constant read”, doesn’t re-derive it with a 64-bit division per dispatch,pit_internal.h:372-375). - The mapping bytes themselves — instructions, constants, shape rows. Read-only pages.
All four are read-only at execution time. Multiple actors executing the same pool share clean, read-only cache lines, which is the ideal case: no coherence traffic beyond the initial fill.
Two caveats on the pin_owner mirror, both stated honestly in its own comment and both
verified:
- Single-owner — and it is only sound because placements are per-runtime.
pin_ownerholds one runtime. The soundness argument is thatPitMachImagePlacements hang offrt->mach_image_placements, so a view can only ever be pinned by the runtime that owns its placement. ManyPitContexts share onePitRuntime(Pit_NewContextRawWithHeapSize(PitRuntime *rt, …),runtime.c:1909/1929), but two runtimes never share a view. If a placement were ever hoisted process-global — a plausible future optimization for the “one pool serving many executables” granularity — the mirror becomes last-writer-wins andmach_binding_is_pinnedstarts refusing live images. This deserves an explicit guard comment onmach_image_placements, because the hoist is exactly the change someone would make for the wrong reason. - Drain race. A pin can drop to zero the instant after the load. Equally true of the locked version. What actually keeps a running image alive is ownership: the frame traces its binding handle, and the handle holds a pin for its whole life.
3.4 Execution path — shared WRITES: on the image lane, ZERO
I looked for every candidate and every one is either unreachable from an image or structurally closed. This is the strongest result in the audit.
| candidate | verdict |
|---|---|
PGO counters (pgo_profile.c:94-100, saturating CAS into a shared table) | Unreachable from an image. mach_exec_pgo returns NULL unconditionally for MACH_EXEC_IMAGE (mach_vm.c:610-612); mach_pgo_observe returns immediately on !session (:876-877); in MACH_PGO_LOADF_* the descriptor is NULL so both the PIC and COLLECT arms are skipped (:4661-4691). Register lane only. |
PitCodeRuntimeMeta + mach_runtime_meta_ensure (mach_vm.c:293-304, a lazy unsynchronized pit_mallocz_rt write) | Hangs off PitCodeRegister. mach_exec_shape/mach_exec_shape_count take the IMAGE branch before dereferencing runtime_meta. Never touched on the image lane. |
cpool_key_hashes (mach_pool.c:2117-2126) | Register lane, at load time, not execution. mach_exec_key_hash (mach_vm.c:599-603) does not consult it for images — it calls pit_key_hash on the stone object. |
PitText.hash memoization — get_text_hash writes text->hash when it reads 0 (pit_text_utf32.c:12-23) | The dangerous one, and it is correctly closed — verified by code, not by comment. Pit_MachPoolOpen → mach_pool_stone_text_section_valid (mach_pool.c:345-357) walks every STONE object at open with verify_hash=1, recomputes the hash and forces it nonzero (mach_pool.c:340: if (!actual_hash) actual_hash = 1;) before comparing. A pool that opens therefore cannot contain a zero-hash stone text, so get_text_hash always short-circuits on the cached value and never attempts a store into the PROT_READ mapping. The claim at mach_vm.c:592-597 holds. |
refcounts / pin_count / open_refs / pin_refs | Shared, all under image_lock. Control plane only. Never touched per call. |
| statistics counters | The dispatch loop’s only atomics are relaxed loads of ctx->profile_enabled and ctx->pause_flag — both per-context (mach_vm.c:3097,3134,3556,4090,…). No stores. |
The one shared write near — but not on — the execution path is buddy_alloc /
buddy_free at GC and heap-growth boundaries (§6.3). That is an allocator event, not a
per-call one.
Cache-line detail that makes the fix worth what it bought: pin_owner sits at
offset 40 in the view — the same line as placement_base, predecessor_abi and
value_row_count, i.e. the other hot reads. open_refs/pin_refs, the fields mutated
under image_lock, land past sections[11] (~545 bytes in). No false sharing between
the hot read and the control-plane refcounts.
3.5 PitCodeRegister / PitCode — a pool creates neither
Pit_NewImageFunction (mach_vm.c:2264-2306) allocates only a PitFunction, with
pit_mallocz_kind(ctx, …, PIT_ALLOC_FUNCTION) — the actor’s own GC heap. No
PitCode, no PitCodeRegister, no pit_rt_ct_alloc. The function is a
(binding, row index) pair plus two actor-heap links. Its header comment is exactly true.
The contrast, worth writing down because it is a loaded gun pointed at the future:
/* source/mach_vm.c:2182-2194 — the REGISTER arm of MACH_CLOSURE */
static PitValue pit_new_register_code(PitContext *ctx, PitCodeRegister *code) {
jc = pit_rt_ct_alloc(ctx->rt, sizeof(PitCode), 8); /* GLOBAL ct_lock, per closure */
Every register-lane closure creation would take the runtime-global ct_lock and
bump-allocate permanently into an arena that is never freed. Today this is
unreachable: grep finds no allocation of a PitCodeRegister anywhere in tree
(the free helper at mach_pool.c:3322 is a bare comment over deleted code), which is
the same fact the code_cache_count gravestone asserts (pit_internal.h:1316-1323,
tests/runtime_arena_counters.cm asserts exactly zero). If the register lane ever
comes back, it brings a global lock and a permanent leak per closure with it. Say so in
the gravestone comment.
pit_new_native_code (mach_vm.c:2199) has the same shape for the QBE lane, but is
memoized per-actor behind st->code_cache (qbe_helpers.c:2176-2181,2210-2214), so it
is once per (dl_handle, fn_idx) per actor. Native lane only.
Dead field, overclaiming comment: PitCodeRegister.code_obj (pit_internal.h:1427)
is commented /* shared OBJ_CODE wrapper for register functions */. There is no read
and no write of it anywhere in C; the design it describes (one ct-arena OBJ_CODE
shared by every actor, plans/archive/roadmap.md:1040) was abandoned. The comment
advertises a sharing that does not exist. Delete the field or the comment.
3.6 The three pool granularities
Confirmed as three, and they differ only in mapping count and pin traffic:
- one pool per module — the loose desktop realize lane.
registry.c:38-41names it explicitly: “loose desktop realization can map one image per unit and therefore has no useful architectural image-count cap”, which is whypinned_mach_imagesis dynamically sized rather than a fixed array. This is the granularity that makes the O(n) pin scan hurt: 149 images ⇒ 149-entry scans. - one pool per executable — the original conception; the press/pack output.
- one pool serving many executables — the boot cart / resident window
(
pit_private_image_provider_adopt_resident,pit_internal.h:471-479), and the fused/resident press image.
Sharing story is identical in all three. Execution reads read-only memory in every
case. What changes is (a) how many placements/ranges exist, hence how long the
image_lock scans are, and (b) how many pin/unpin operations the control plane performs.
Coarser pools are strictly better for both. There is no case in which two actors write
the same pool memory.
4. Cross-actor channels
4.1 By design — correct, keep
| channel | mechanism | verdict |
|---|---|---|
| letters / mailbox | target->letters under target->msg_mutex, blob payloads copied (send_message, scheduler.c:4192-4245) | by design. Wota-encoded copy, no pointer sharing. |
| run queues | engine.q_head/q_tail[4], main_q_*, per-lane queues under engine.lock | by design, but a single global lock — §6.1 |
| actor registry | actors / starting_actors under actors_mutex | by design, but on the send path — §6.1 |
| stop watchers | stop_watchers under the watchers_mutex leaf lock | by design; the leaf-lock discipline (scheduler.c:850-868) is exactly right and fixed a real AB-BA deadlock |
| timers | timer_heap under engine.lock | by design |
| parks / signals / call gates | per-actor lists, _Atomic state CAS under the owning actor’s msg_mutex | by design, correct |
pit_ring SPSC rings | per-endpoint _Atomic read/write positions (pit_ring.h:69-72) | by design, lock-free SPSC, correct |
$inspect / scheduler_snapshot | one actors_mutex walk taking a refcount on each actor (scheduler.c:2936-2957) | by design, correct — one lock, one walk, no lock ordering |
4.2 Acceptable — counters and cookies
rt->identity, pit_runtime_identity_next, g_pgo_snapshot_generation,
pgo_disabled_sites, next_execution_lane_driver_token, buddy accounting fields,
shape_count/shape_bytes, cfunc_cache_*. None reachable from pit code; all either
atomic or under the lock that guards the thing they describe.
4.3 The cfunc_lock cache — actors DO receive shared PitValues. Is it safe?
Yes, and here is why, with the caveat.
pit_new_cfunc_internal (runtime.c:2347-2399) hands the same PitValue to every
actor that registers the same (fnptr, name, arity, proto, magic). The pointed-at
PitFunction is:
- allocated in the ct arena (
pit_rt_ct_alloc) — off every actor’s GC heap, never moved (the collector’sis_ct_ptrgate refuses to copy it); - created with
objhdr_make(…, /*stone=*/true)— so the language cannot mutate it; - written exactly once, before publication, under
cfunc_lock; - kind
PIT_FUNC_KIND_C: it holds a raw C function pointer, an arity, a magic, and a name key that is itself an immortal ct-pool text. It holds no actor-heap pointer, so it cannot be a bridge between two actor heaps.
So it is a shared immutable — the same category as image constants, and safe for the same reason. It is not a channel: nothing an actor does can change what another actor reads out of it.
Caveat (perf, not safety): the cache is a singly-linked list scanned with strcmp
under a runtime-global mutex on every Pit_NewCFunction2, and every actor
re-registers every C function of every module it uses at start. With M actors and F
C functions that is M×F acquisitions of cfunc_lock, each doing an O(F) strcmp walk.
For the fleet (77 actors) this is measurable actor-start cost. See §6.6.
4.4 The nan32 opaque_lock table — a real channel, and a real hot path on nan32
rt->opaque_values is a runtime-global side table mapping a 32-bit handle to a
native void*, because nan32 values cannot carry a host pointer.
rec_opaque()/rec_set_opaque() (pit_internal.h:1775-1788) call
pit_opaque_handle_get/_set (runtime.c:274-283, 312+), each of which takes
rt->opaque_lock.
Two things follow:
- Performance: on nan32, every
Pit_GetOpaqueon a class record (every file read, socket op, child-process op, every provider handle deref) takes a runtime-global mutex. This is theimage_lockshape, on the nan32 arm, undiscovered because nan32 has never been run under a parallel fleet. - Isolation: the handle space is shared. A handle is a plain
uint32_tliving in a record. It is not reachable as a language value (records expose no accessor foropaque_handle), so pit code cannot forge one. But a C module that mis-handles a handle can reach another actor’s native resource, which nan64 (where the pointer lives in the record itself) structurally cannot. Worth stating indocs/.
4.5 The native lane’s shared template caches (qbe_helpers.c) — safe, worth knowing
Two structures live in a generated native module’s writable data section, shared by
every actor that calls that module. Both are compiled in for darwin/linux/windows
(cake/plan.cm:768-773 selects qbe_helpers.c when the recipe has
capabilities.native_payload; the three dev manifests all include it), but only
exercised when a native payload actually runs — which the no-AOT ruling means is not
the current lane.
AOTGenericRecordTemplate(qbe_helpers.c:638-696) —_Atomic uint32_t state4-state priming CAS (0 unprimed → 1 priming → 2 good / 3 refused), with a spin loop on state==1 for losers (:692-695). Primed once, then read-only. The comment admits the priming “now fails for every real template” since the packed-text lane went, so it is effectively dead.AOTRecordTemplate(qbe_helpers.c:723-795) —_Atomic uint32_t runtime_id+_Atomic uintptr_t shape, a most-recently-active-runtime cache over a sharedPitRecordShape. The hot path (:780-795) is two acquire loads and no write; the cold path (:734-778) interns keys, builds a shape, and republishes withUINT32_MAXas a transient writer sentinel. The double-read ofruntime_idaroundshapeis deliberate and correct: it stops one runtime’s cookie pairing with another runtime’s descriptor.
Verdict: safe — read-mostly, atomics, and the values published are immortal shared constants, not actor-heap pointers. Note only that the cold path is a process-global mutable cache keyed on the current runtime, so a two-runtime embedder ping-pongs it. The comment says so.
4.6 Violations of the isolation model
None where pit code is concerned. I found no shared mutable structure reachable from the language. Every shared thing is either (i) stone/immortal (ct pool, shapes, cfuncs, image constants), (ii) engine plumbing not exposed as a value (queues, registry, watchers, ranges), or (iii) counters.
The violations that exist are C-level races, listed next.
5. C-level races found (bugs, not design problems)
5.1 pit_class_id_alloc — unsynchronized global ++ (real, memory-safety-adjacent)
runtime.c:53 PitClassID pit_class_id_alloc = PIT_CLASS_INIT_COUNT;
runtime.c:2222 class_id = pit_class_id_alloc++;
Pit_NewClassID is called from native module registration, which runs inside
script_startup (pit.c:145) — and script_startup is called from
boot_actor_shell_with_mach_ownership (scheduler.c:3979) holding only
actor->mutex, the starting actor’s own mutex.
Concurrency chain, verified end to end: pit_actor.c:196 (run_boot, an ordinary C
function callable from pit code) → boot_actor_shell_with_mach → script_startup.
run_boot runs inside the calling actor’s turn, on whatever worker thread that actor
was scheduled on. Two actors calling run_boot on two workers therefore run
script_startup — and Pit_NewClassID — genuinely concurrently.
Compounding it: the per-module holders are themselves lazy-init statics with a
read-check-write, e.g. image_provider.c:72-75 + :353-357, and
Pit_NewClassID only allocates if (*pclass_id == 0) — a classic double-checked
init with no barrier.
Consequence if it fires: two distinct classes get the same PitClassID.
Pit_GetOpaque (runtime.c:3052-3061) authenticates on class_id alone, so it
would accept a record of the wrong class and hand back its void* reinterpreted as the
wrong struct. That is arbitrary memory corruption inside one actor.
Fix: make it _Atomic PitClassID with atomic_fetch_add, and make the per-module
holders a CAS-published _Atomic PitClassID (allocate, CAS 0→id, on failure free the id
and use the winner’s). ~20 lines total. Low risk. Should be done.
5.2 g_log_actor_id — free-while-read (real)
scheduler.c:93 is a char* that system_log_set_actor (:116-119) frees and
strdups, and that system_log_active (:130-132) and is_log_actor (:155)
read/strcmp from other threads with no lock. The long comment (:121-131) argues
convincingly about staleness but says nothing about the free. A logger that dies
while another thread is inside strcmp(g_log_actor_id, …) is a use-after-free.
Fix: _Atomic(char*) with the old pointer retired rather than freed (or an
actors_mutex-style tiny lock; the path is not that hot). ~15 lines.
5.3 Two unsynchronized global_timer_id counters
scheduler.c:3318 (unneeded-countdown arm) and scheduler.c:5029
(actor_add_timer). Both static uint32_t global_timer_id = 1; id = global_timer_id++;
and both increment before taking engine.lock. They are also two separate
counters, so the two paths hand out overlapping ids by construction.
actor_remove_timer(actor, timer_id) matches on actor and id, so a collision
between two actors is harmless; a collision for the same actor cancels the wrong
timer. Low severity, trivial fix: one _Atomic uint32_t shared by both sites.
5.4 pit_tick_drain_head — unsynchronized list push, never removed, never deduped
registry.c:400-408. e->next = head; head = e; with no lock — a lost-update race if
two actors initialize a drain-registering module concurrently. Worse, the header comment
says modules register “during their normal initialization path”, which is per actor: N
actors using the module ⇒ N identical entries ⇒ pit_run_tick_drains calls the same
function N times per pit_drain, and nothing is ever freed. Today only wgpu-class
modules use it, so it is latent.
Fix: CAS the head, and dedupe on fn. ~10 lines.
5.5 is_ct_ptr reads rt->ct_pages unlocked (benign-by-construction, worth a note)
pit_internal.h:2967-2979 walks the ct_pages linked list with no lock, from
pit_ptr_in_actor_space — which is called on VM paths (mach_vm.c:1516,1522,1744) and
per-slot inside the collector (pit_gc_copy.c:1175,1692). Writers push under ct_lock
(runtime.c:494-503, reached only via pit_rt_ct_alloc and the two ct_lock-holding
callers), and the push publishes page->next before head, so a reader sees either the
old chain or the new one — both valid. It is UB by the letter of C11 and a data race
under TSan, but it cannot produce a wrong answer on any platform in play.
Note also that the list is only reached when ct_base is exhausted (the primary arena
covers everything in a normal daemon), and only for pointers not in the actor’s own
heap/nursery/frames, because those disjuncts short-circuit first. So the walk is
essentially never taken. Making ct_pages _Atomic is a one-word change if you want
TSan cleanliness.
6. Verdict — ranked
(i) Hot-path shared facts that should be per-actor or lock-free
6.1 — actors_mutex + engine.lock on every message send. THE next image_lock.
send_message (scheduler.c:4192) → scheduler_ref_actor(id) takes the process-global
actors_mutex and does a string-hash lookup; then target->msg_mutex; then
set_actor_state → enqueue_actor_priority takes the process-global engine.lock
to push onto one of four shared queues and signal a condvar. Every worker also takes
engine.lock to dequeue. So each inter-actor message costs two global lock
acquisitions plus a condvar signal, and every turn costs another.
With the image lock gone, this is now the only remaining O(1)-per-message global
serialization point in a 77-actor fleet. The post-fix profile’s __psynch_cvwait at
107,966 samples is consistent with threads parked on engine.wake_cond — i.e. the queue
is now the thing they wait on. (I did not measure; this is a code-shape prediction, and
it should be measured before it is fixed.)
Fix direction: (a) hand callers a refcounted PitContext* handle at couple time so
the steady-state send skips the registry lookup entirely — the id→ctx map is only needed
for the first resolution; (b) shard engine.lock/the run queues per worker with
work-stealing, or at minimum split the timer heap off engine.lock onto its own mutex so
the timer thread stops contending with every enqueue. Size: (a) medium, ~200 lines and
a lifetime argument; (b) large, a scheduler rework. Measure first. Cheapest first
step that is certainly right: give timer_heap its own lock — small, mechanical.
6.2 — image_lock is still an O(n) scan at every pin/unpin.
registry.c:72-156. Loose per-module realization pins ~149 images; each pin/unpin scans
the whole array under the runtime-global lock, so the load phase is quadratic and
serialized. Not on the call path any more, but it is the same lock and the same scan.
Fix direction: the range array wants to be a small open-addressed hash keyed on the
view pointer, or — simpler and better — put the PitPinnedMachImageRange inline in the
placement and give the view a direct pointer to its own range, making pin/unpin O(1)
with an atomic pin_count and the lock needed only for array growth. Size: ~80 lines,
low risk, the C regressions (mach_image_lifetime_test.c,
resident_image_provider_test.c, mach_pool_test.c:1285) already cover the invariant.
6.3 — buddy.lock is the one global lock on the GC path.
Every actor heap block, nursery grow, and copy/compact destination block goes through
buddy_alloc/buddy_free, which take rt->buddy.lock and walk the pool list. With 77
actors collecting independently this is a genuine serialization point at GC boundaries —
not per allocation (per-object allocation is a pure bump in the actor’s own arena), but
per GC cycle and per heap resize, which under a compile fleet is frequent.
Fix direction: a per-actor free-list cache in front of the buddy (an actor returning a
block of order k keeps it for its own next request), or size-class-sharded buddy locks.
Size: small for the cache (~60 lines), medium for sharding. Measure first — this is
a prediction from code shape, not from a profile.
6.4 — nan32 opaque_lock on every Pit_GetOpaque. §4.4. Only bites the nan32 arm,
which is not the arm under fleet load today, but it is structurally the same bug class as
image_lock and should be fixed before nan32 ever runs a parallel fleet.
Fix direction: a per-actor handle table (handles are already opaque and never cross
actors), or a lock-free open-addressed table with a generation tag.
Size: medium, ~150 lines, nan32-only blast radius.
6.5 — the PGO collector’s shared counters (§3.4). Latent, and further away than I
first thought: the image lane cannot reach it at all (mach_exec_pgo → NULL). It is a
register-lane structure, and the register lane is itself dead. Do not turn PGO collection
on broadly, on any lane, without per-actor counter shards merged at snapshot.
6.6 — cfunc_lock linear strcmp scan per C-function registration per actor start.
§4.3. Not per call, but M×F under one global lock at fleet start-up.
Fix direction: key the cache by the C function pointer in a small hash rather than a
list, and skip the pit_key_new before the lookup (it interns the name into the ct pool
before discovering the entry already exists — runtime.c:2351 runs unconditionally).
Size: ~50 lines. Easy win.
6.7 — actor start re-hashes the whole pool it is about to share. Not a sharing
defect but the largest lifecycle cost the sharing model fails to save.
provider_adopt_bytes blake2b’s the entire window (image_provider.c:878) and
Pit_MachPoolOpen re-validates every STONE text’s hash (mach_pool.c:684) — both
before the placement dedup lookup that would have told it the answer is already known.
Every actor starting an already-mapped pool pays O(pool bytes) twice over. The file path
also mmap/munmaps per call around the dedup (image_provider.c:484).
Fix direction: move the dedup probe ahead of the hashing — the (placement_id, artifact_hash) key is available from the caller in the resident/plan path, and on the
file path a (dev, ino, size, mtime) pre-probe is enough to skip the map+hash. Keep full
validation for the first adopter; it is the repeat adopters that are paying for
nothing. Size: ~60 lines, medium risk (the validation ordering is a security boundary —
do not let a second adopter skip validation of a different byte range; key strictly).
(ii) Shared state that contradicts the stated model
Interned text: no contradiction. §2. The model holds. The only thing worth doing is
documentary: the ct_lock comment sits at the top of a block that also covers shape
rows, PitFunctions and PitCodes, which makes the pool look like a general text
intern table when it is really “the immortal-constant arena, of which text is one
tenant”. Renaming the block comment would stop the next reader (and the next John)
worrying.
One genuine model deviation: pin_owner assumes one runtime per view (§3.3). It is
fail-safe rather than fail-open, so it is a documentation/assert item, not a bug.
One structural deviation on nan32 only: the opaque handle table is genuinely shared
state where nan64 has none (§4.4). It is not reachable from pit code, but it is a real
asymmetry between the profiles and should be written down in docs/architecture/.
Overclaiming comments to correct while you are in there (each is a sentence, but each would mislead the next reader about sharing):
pit_internal.h:433-436—pit_runtime_contains_pinned_mach_pointer“is used only by GC and diagnostics”. The GC does not call it; it has zero non-test callers.pit_internal.h:1427—PitCodeRegister.code_obj“shared OBJ_CODE wrapper”. Never read, never written, anywhere. Dead field advertising a sharing that was abandoned.pit_internal.h:1290-1292— “Runtime-wide immutable text pool… safe to reference from any actor.” True but it heads a block that also covers shape rows,PitFunctions andPitCodes. It reads as a general text intern table. Rename it to what it is: the immortal-constant arena, of which interned text is one tenant.registry.c:12— “No thread safety: the static table is installed once during startup.” Accurate for the extension table, but the same file also hosts the lease list and the tick-drain list, and a reader takes the sentence as covering the file.pit_internal.h:1316-1323(the register-lane gravestone) — add that the lane’s return would also reintroduce a runtime-globalct_lockacquisition and a permanent shared-arena allocation per closure (§3.5). Right now the gravestone only warns about the counters.
(iii) Confirmed clean — stop worrying about these
- Execution out of mapped pools. One atomic load per call, everything else read-only,
and I enumerated every shared-write candidate and found zero reachable from the
image lane (§3.4). N actors on one pool cause zero coherence traffic.
pin_ownerdoes not even false-share with the control-plane refcounts. This is now genuinely right. - Pool granularity. Per-module / per-executable / many-executables differ only in mapping count and pin traffic. No granularity introduces a shared write.
- The stone-text hash memoization, which was the one place an executing actor could
plausibly have written into shared (and read-only!) pool memory. Closed at open by
forced-nonzero hash validation of every STONE object (
mach_pool.c:340). - Image function creation.
Pit_NewImageFunctionallocates onePitFunctionon the actor’s own heap and nothing else. No shared allocation, no ct arena, no lock. - Record key lookup.
pit_key_equal/pit_key_hash/rec_find_slot_hashed/pit_mach_record_get_hashedtouch actor-local memory and immortal read-only text. No lock on the read path, and none needed. The profile leaves are honest work. - Ordinary text creation. Actor heap, always. No interning, no shared writes.
- The garbage collectors. Both
pit_gc_copy.candpit_gc_compact.ckeep 100% of their working state in__threadvariables, deliberately and with a comment saying why. There is not one shared mutable byte in either collector besidesbuddy.lock. PitContextisolation. Per-actor heap, per-actorclass_array, per-actor mailbox/parks/signals, non-transferablePITCLASSrecords. No actor-heap pointer leaves an actor.code_cache_count/code_cache_bytes. Verified: no writer in tree. The gravestone is intact.- Region table. Install-once behind an atomic latch;
pit_region_findhas zero non-test callers. - Static extension/endowment tables. Install-once, read-only.
Top 3 fixes, in order
- Get the message path off the two global locks (§6.1) —
actors_mutex+engine.lockper send is the only remaining O(1)-per-message global serialization in a 77-actor fleet, and it is the shapeimage_lockhad. Measure first (the code shape predicts it; nothing has profiled it since the pin fix moved the bottleneck). Cheapest correct first step: givetimer_heapits own mutex so the timer thread stops contending with every enqueue. Then refcounted context handles at couple time to skip the registry lookup on the steady-state send. - Make pin/unpin O(1) and stop re-hashing shared pools at every actor start
(§6.2 + §6.7) — one arc: put the
PitPinnedMachImageRangeinline in the placement with an atomicpin_count(lock only for array growth), and move the placement dedup probe ahead of the blake2b + STONE re-validation. ~140 lines together; the C regressions (mach_image_lifetime_test.c,resident_image_provider_test.c,mach_pool_test.c:1285) already cover the pin invariant. This is the row that makes loose per-module realization stop being quadratic. - Fix
pit_class_id_alloc(§5.1) — atomic counter + CAS-published per-module ids. ~20 lines, and it closes a type-confusion path thatPit_GetOpaquecannot defend against, because it authenticates onclass_idalone.
Runners-up, all small and independent: g_log_actor_id free-while-read (§5.2),
pit_tick_drain_head (§5.4), the cfunc_lock scan (§6.6), the two global_timer_id
counters (§5.3), and the five overclaiming comments listed above.
7. What I did not do
- No measurement. Every performance claim in §6.1 and §6.3 is a prediction from code
shape. §6.2/§6.7 are counted lock acquisitions and counted hashes, which is stronger,
but still not a profile. The one measured fact in this document is the pin-lock fix’s
own before/after, quoted from
plans/archive/night-2026-08-04/seed-speed.md. - No
platform/sweep. The audit coveredsource/. Per-OS providers underplatform/<os>/may hold their own file-scope state (the posix signal/loop machinery is the likely candidate). Worth a second pass. - No TSan run. §5.1-§5.5 are read off the code. A ThreadSanitizer build of a parallel press would confirm or refute all five in one run, and would be the honest next step before touching any of them.
Source: plans/proposal-notes/runtime-sharing-audit.md