#![expect(
clippy::unwrap_used,
reason = "ratchet MOIRAI-UNWRAP-1: pre-existing debt"
)]
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Condvar, MutexGuard};
use super::channel::MpmcChannel;
use super::{MPMC_BLOCK_SPINS, MpmcState};
#[inline]
pub(super) fn backoff_step(round: &mut usize) {
for _ in 0..(1 << *round) {
std::hint::spin_loop();
}
*round += 1;
}
impl<T: Send> MpmcChannel<T> {
pub(super) fn wait_while<'a>(
&'a self,
mut guard: MutexGuard<'a, MpmcState<T>>,
condvar: &Condvar,
waiters: &AtomicUsize,
blocked: impl Fn(&MpmcState<T>) -> bool,
) -> MutexGuard<'a, MpmcState<T>> {
let mutex = &self.state.0;
let mut round = 0;
while blocked(&guard) {
if round < MPMC_BLOCK_SPINS {
drop(guard);
backoff_step(&mut round);
guard = mutex.lock().unwrap();
} else {
waiters.fetch_add(1, Ordering::AcqRel);
guard = condvar.wait(guard).unwrap();
waiters.fetch_sub(1, Ordering::AcqRel);
}
}
guard
}
}