use core::sync::atomic::{AtomicU64, Ordering};
pub(crate) enum FastLockAttempt {
Acquired,
Contended,
}
pub(crate) enum LockEntry<T> {
Acquired,
Contended(T),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum FastReleaseAttempt {
Released,
Contended,
InvalidOwner,
}
#[inline(always)]
pub(crate) fn capture_current_and_prepare_slow<T>(
capture_current: impl FnOnce() -> T,
try_fast: impl FnOnce(&T) -> FastLockAttempt,
validate_blocking_context: impl FnOnce(),
) -> LockEntry<T> {
let current = capture_current();
match try_fast(¤t) {
FastLockAttempt::Acquired => LockEntry::Acquired,
FastLockAttempt::Contended => {
validate_blocking_context();
LockEntry::Contended(current)
}
}
}
pub(crate) fn try_release_current_owner_word(
owner: &AtomicU64,
current: u64,
owner_id_mask: u64,
) -> FastReleaseAttempt {
if current == 0 || current & !owner_id_mask != 0 {
return FastReleaseAttempt::InvalidOwner;
}
match owner.compare_exchange(current, 0, Ordering::Release, Ordering::Relaxed) {
Ok(_) => FastReleaseAttempt::Released,
Err(owner_word) if owner_word & owner_id_mask == current => FastReleaseAttempt::Contended,
Err(_) => FastReleaseAttempt::InvalidOwner,
}
}
pub(crate) fn owner_spin_eligible(
cpu_count: usize,
observe_progress_gates: impl FnOnce() -> bool,
) -> bool {
cpu_count > 1 && observe_progress_gates()
}
pub(crate) fn owner_spin_progress_gates(
same_owner: bool,
owner_on_cpu: bool,
waiter_is_top: bool,
need_resched: bool,
) -> bool {
same_owner && owner_on_cpu && waiter_is_top && !need_resched
}