use std::{
sync::{Condvar, Mutex},
time::Instant,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WatchdogOutcome {
Finished,
DeadlineReached,
}
#[derive(Debug)]
pub struct WatchdogSignal {
finished: Mutex<bool>,
changed: Condvar,
}
impl WatchdogSignal {
#[must_use]
pub const fn new() -> Self {
Self {
finished: Mutex::new(false),
changed: Condvar::new(),
}
}
pub fn finish(&self) {
let mut finished = self.finished.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
*finished = true;
drop(finished);
self.changed.notify_all();
}
#[must_use]
pub fn is_finished(&self) -> bool {
*self.finished.lock().unwrap_or_else(std::sync::PoisonError::into_inner)
}
pub fn wait_until(&self, deadline: Instant) -> WatchdogOutcome {
let mut finished = self.finished.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
loop {
if *finished {
return WatchdogOutcome::Finished;
}
let remaining = deadline.saturating_duration_since(Instant::now());
if remaining.is_zero() {
return WatchdogOutcome::DeadlineReached;
}
let (guard, _) = self
.changed
.wait_timeout(finished, remaining)
.unwrap_or_else(std::sync::PoisonError::into_inner);
finished = guard;
}
}
}
impl Default for WatchdogSignal {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests;