Two integration-driven amendments ahead of the runtime swap: wake_one_if_idle() realizes RFC 018's "empty-mask fast path is one relaxed load" soundly: a bare relaxed load is a lost-wake in the Dekker shape for the lock-free ring queues, so the producer publishes work, fences (SeqCst), then reads the mask Relaxed — paired with a matching fence between the consumer's bit-publish and its re-check in park(). The pure-compute hot path (mask 0) never takes the shared mask line exclusive; the RMW read stays on the rare chain-rule path only. Loom models 1/2 now drive the fenced pattern end to end. next_deadline is the earliest KNOWN timer deadline, independent of whether anyone is parked — which tk_armed cannot give: under saturation nobody parks, nobody arms, yet due timers must still fire (ratified design point (a): the busy-path due-check). Maintained under the timers mutex (note_deadline on insert — which also carries the timekeeper re-arm wake — refresh_deadline after pop/clear); read lock-free. deadline_due() costs one Relaxed load and a branch when no timer exists; the clock is read only when one does.
47 lines
1.5 KiB
Rust
47 lines
1.5 KiB
Rust
//! std vs loom indirection for the modules that loom model-checks
|
|
//! (`slot_state`, `run_queue`). Everything else uses std paths directly —
|
|
//! the full runtime (context switches, futexes, real TLS) is not loom-able
|
|
//! and is never executed under `cfg(loom)`.
|
|
//!
|
|
//! Build the loom models with: `RUSTFLAGS="--cfg loom" cargo test --lib --release`
|
|
|
|
#[cfg(loom)]
|
|
pub(crate) use loom::sync::atomic::{fence, AtomicU64, AtomicUsize, Ordering};
|
|
|
|
#[cfg(not(loom))]
|
|
pub(crate) use std::sync::atomic::{fence, AtomicU64, AtomicUsize, Ordering};
|
|
|
|
// park.rs condvar-parker (loom + non-Linux builds only; the Linux non-loom
|
|
// build parks on a futex and never touches these — gating them identically
|
|
// keeps the default build free of unused imports).
|
|
#[cfg(loom)]
|
|
pub(crate) use loom::sync::{Condvar, Mutex};
|
|
|
|
#[cfg(all(not(loom), not(target_os = "linux")))]
|
|
pub(crate) use std::sync::{Condvar, Mutex};
|
|
|
|
/// `UnsafeCell` with loom's `with`/`with_mut` access API; pass-through cost
|
|
/// is zero in normal builds (`#[inline]`, newtype over std's cell).
|
|
#[cfg(loom)]
|
|
pub(crate) use loom::cell::UnsafeCell;
|
|
|
|
#[cfg(not(loom))]
|
|
pub(crate) struct UnsafeCell<T>(std::cell::UnsafeCell<T>);
|
|
|
|
#[cfg(not(loom))]
|
|
impl<T> UnsafeCell<T> {
|
|
pub(crate) fn new(v: T) -> Self {
|
|
Self(std::cell::UnsafeCell::new(v))
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn with<R>(&self, f: impl FnOnce(*const T) -> R) -> R {
|
|
f(self.0.get())
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn with_mut<R>(&self, f: impl FnOnce(*mut T) -> R) -> R {
|
|
f(self.0.get())
|
|
}
|
|
}
|