Expand description
Monitor-based wait tier: hardware MONITOR/MWAIT-class waiting between the spin tier and the kernel-park tier.
The wait ladder this slots into:
| Tier | Mechanism | Wait scale | Core while waiting | Producer wake cost |
|---|---|---|---|---|
| spin | PAUSE loop | ns | busy | free (the store) |
| monitor (this module) | MONITORX/MWAITX (AMD) or UMONITOR/UMWAIT (WAITPKG) | us, bounded | light sleep (C0.1) | free (the store) |
| park | futex / _umtx_op / WaitOnAddress | unbounded | released to the OS | one syscall |
The monitor tier’s two properties the other tiers lack:
- The producer’s wake is free. The waiter arms a hardware monitor on the slot’s cache line; ANY store to that line trips it. The producer’s existing state-CAS IS the wake - no syscall on the wake side, unlike every kernel-park mechanism.
- Monitors are physical-address based (AMD APM / Intel SDM
MONITOR semantics), so a store from ANOTHER PROCESS that
mapped the same MMF page wakes the waiter. On Windows - where
WaitOnAddressis intra-process only - this is the first non-polling cross-process wake the substrate has.
What it is NOT: a park. MWAITX / UMWAIT hold the core in a
shallow sleep state with a hardware deadline; the OS cannot
schedule other work there. The tier therefore takes a bounded
cycle budget and reports false on expiry so the caller
escalates to the kernel park.
§Instruction facts (verified against the Linux kernel’s
arch/x86/include/asm/mwait.h and the Intel SDM UMWAIT page)
MONITORX: address inrAX,ECX= extensions (0),EDX= hints (0). Both extension registers MUST be zero - nonzero raises #GP, and the Windows x64 ABI happily leaves argument garbage inRCXif the wrapper does not pin it.MWAITX:EAX= hints (0),EBX= max wait “expressed in SW P0 clocks; the software P0 frequency is the same as the TSC frequency”,ECXbit 1 = enable the timer.UMONITOR r64: address operand.UMWAIT r32: register operand = control (bit 0: 1 = C0.1 shallow/fast wake, 0 = C0.2 deeper; other bits #GP); implicitEDX:EAX= ABSOLUTE TSC deadline; wakes on monitored store, deadline, or the OS’sIA32_UMWAIT_CONTROLcap (CF set).- Detection: MWAITX = CPUID
0x8000_0001ECX bit 29 (AMD); WAITPKG = CPUID7.0ECX bit 5 (Intel Tiger Lake+ / Sapphire Rapids+, AMD Zen 5+).
Both waits can wake spuriously (interrupts trip monitors), so the loop re-arms until the value changes or the budget expires.
§Tuning
SUBETHA_NO_MONITOR_WAIT=1disables the tier (callers fall straight from spin to park).SUBETHA_MONITOR_WAIT_CYCLES=<n>overrides the default per-wait budget (DEFAULT_MONITOR_BUDGET_CYCLES).
Enums§
- Monitor
Wait Kind - Which monitor-wait instruction family this host runs.
Constants§
- DEFAULT_
MONITOR_ BUDGET_ CYCLES - Default monitor-tier budget in TSC cycles before escalating to the kernel park: ~25-30 us on contemporary 3-3.5 GHz parts. Sized to dominate a kernel park+wake round trip (single-digit us) so waits that resolve quickly never pay the syscall, while a genuinely idle waiter escalates to the zero-CPU park within tens of microseconds.
Functions§
- monitor_
wait_ budget_ cycles - The active per-wait budget in TSC cycles.
- monitor_
wait_ kind - The monitor-wait family available on this host (
Nonewhen the CPU exposes neither, when the build target is not x86_64, or whenSUBETHA_NO_MONITOR_WAIT=1). Cached after the first call. - monitor_
wait_ u32 - Wait on the monitor tier until
*atomic != expectedor the cycle budget expires. - monitor_
wait_ u64 - As
monitor_wait_u32for a 64-bit atom (ring head counters and slot sequences areAtomicU64). Same protocol, same guarantees: the monitor watches the LINE, the width only affects the value re-check. - monitor_
wait_ u32_ with - As
monitor_wait_u32with the family chosen explicitly (bench harnesses A/B the families; production callers use the probed default). - monitor_
wait_ u64_ with