use std::sync::atomic::Ordering;
use std::time::Duration;
#[derive(Debug, Clone, Copy)]
enum SleepStepPolicy {
Stop(bool),
Continue { slice: Duration },
}
fn compute_sleep_policy(
should_stop: bool,
now: std::time::Instant,
deadline: std::time::Instant,
poll_interval: Duration,
) -> SleepStepPolicy {
if should_stop {
SleepStepPolicy::Stop(true)
} else if now >= deadline {
SleepStepPolicy::Stop(false)
} else {
let remaining = deadline.saturating_duration_since(now);
let slice = poll_interval.min(remaining);
SleepStepPolicy::Continue { slice }
}
}
fn sleep_poll_step(
should_stop: &std::sync::atomic::AtomicBool,
deadline: std::time::Instant,
poll_interval: Duration,
) -> Option<bool> {
let stop_flag = should_stop.load(Ordering::Acquire);
let now = std::time::Instant::now();
match compute_sleep_policy(stop_flag, now, deadline, poll_interval) {
SleepStepPolicy::Stop(ret) => Some(ret),
SleepStepPolicy::Continue { slice } => {
std::thread::sleep(slice);
None
}
}
}
pub fn sleep_until_next_check_or_stop(
should_stop: &std::sync::atomic::AtomicBool,
check_interval: Duration,
) -> bool {
let poll_interval = check_interval.min(Duration::from_millis(100));
let deadline = std::time::Instant::now() + check_interval;
loop {
if let Some(result) = sleep_poll_step(should_stop, deadline, poll_interval) {
return result;
}
}
}