Expand description
Dynamic-linking (Dl*) synchronization for the WASIX super::Linker.
Instance groups run on different OS threads and share one super::LinkerState behind an
std::sync::RwLock. Operations that change “who exists” or “what every group must agree on”
must coordinate with both that lock and a stop-the-world style broadcast of concrete mutations
(DlOperation). This module holds the primitives that make that safe.
§Locks and responsibilities
-
Instance-group mutex (
lock_instance_group_state!,Linker::instance_group_state): Per-super::Linkerhandle to this thread’s [InstanceGroupState]. Many linker entry points take it first so they can call into group-local state and, when needed, run cooperative DL helpers with the rightStore/ [FunctionEnv]. -
Topology lease (
LinkerSharedholdstopology_lock::TopologyCoordinatorprivately): A single-writer gate for topology-changing work (new instance groups, module loads, export resolution that can allocate shared slots, etc.). The lease is acquired in a cooperative loop with backoff and pending-DL cooperation (seeLinkerShared::acquire_topology_token,LinkerShared::write_linker_state_with_topology).TopologyTokenmay move to another thread (spawn handoff). -
Shared linker state (inside
LinkerShared, not exposed as a field): Global module table, symbol records, and the buses used to broadcastDlOperationand barriers. Writers must follow the cooperative patterns below—not raw lock calls. -
Pending-DL handshake (
dl_operation_pending, barriers, wakeup signals): While an instigator runsLinkerShared::synchronize_link_operation, follower threads must enter [Linker::do_pending_link_operations] (or helpers) so everyone rendezvouses. That is why contended access to [LinkerState] cannot spin blindly.
§Lock ordering (intended)
When topology applies: topology token first, then lock [LinkerState] for write via the APIs
in this module—not the inverse. Never try to acquire a topology lease from inside code that
already holds [LinkerState] for write without a deliberate, reviewed plan (easy deadlock).
§Why you must never lock LinkerState directly
Do not call linker_state.read(), write(), or try_write() on [Linker]’s [RwLock] from
normal instance-group linker paths. Doing so skips the cooperative path and can deadlock the
whole process: another thread may hold the write lock while waiting at a DL barrier for this
thread to execute LinkerShared::do_pending_link_operations_internal, which requires the same group
context and cannot run if this thread is stuck in a naive blocking write().
Use instead:
LinkerShared::write_linker_state—try_writeloop +LinkerStateWriteBackoff+ pending-DL draining.LinkerShared::write_linker_state_with_topology— topology lease + draining + blocking write when topology must be serialized before grabbing [LinkerState].LinkerShared::write_linker_state_blocking_holding_topology— blocking write only while already holdingTopologyToken, after topology was leased on another thread/step.
Narrow exceptions (e.g. one-off bootstrap in super::Linker::new before other groups exist)
belong in tightly scoped code and should still avoid contending paths that overlap DL sync.
Modules§
- linker_
shared 🔒 - Shared dynamic-link state for every
super::super::Linkerclone. - topology_
lock 🔒 - Single-writer gate for WASIX linker topology changes.
Macros§
Structs§
- Linker
State 🔒Write Backoff - Spin, then yield, then capped exponential sleep — for cooperative linker-state retries.