use std::sync::{Condvar, Mutex};
use std::time::Instant;
struct WfiState {
irq_pending: bool,
stopped: bool,
monitor_wake: bool,
deadline: Option<Instant>,
}
pub struct WfiWaker {
state: Mutex<WfiState>,
cv: Condvar,
}
impl WfiWaker {
pub fn new() -> Self {
Self {
state: Mutex::new(WfiState {
irq_pending: false,
stopped: false,
monitor_wake: false,
deadline: None,
}),
cv: Condvar::new(),
}
}
pub fn wake(&self) {
let mut s = self.state.lock().unwrap();
s.irq_pending = true;
self.cv.notify_all();
}
pub fn monitor_wake(&self) {
let mut s = self.state.lock().unwrap();
s.monitor_wake = true;
self.cv.notify_all();
}
pub fn clear_monitor_wake(&self) {
let mut s = self.state.lock().unwrap();
s.monitor_wake = false;
}
pub fn stop(&self) {
let mut s = self.state.lock().unwrap();
s.stopped = true;
self.cv.notify_all();
}
pub fn set_deadline(&self, deadline: Instant) {
let mut s = self.state.lock().unwrap();
s.deadline = Some(deadline);
self.cv.notify_all();
}
pub fn clear_deadline(&self) {
let mut s = self.state.lock().unwrap();
s.deadline = None;
}
pub fn wait(&self) -> bool {
let mut s = self.state.lock().unwrap();
loop {
if s.irq_pending {
s.irq_pending = false;
return true;
}
if s.stopped {
return false;
}
if s.monitor_wake {
s.monitor_wake = false;
return true;
}
if let Some(deadline) = s.deadline {
let now = Instant::now();
if now >= deadline {
s.deadline = None;
return true;
}
let remaining = deadline - now;
let (new_s, result) =
self.cv.wait_timeout(s, remaining).unwrap();
s = new_s;
if result.timed_out() {
s.deadline = None;
return true;
}
} else {
s = self.cv.wait(s).unwrap();
}
}
}
}
impl Default for WfiWaker {
fn default() -> Self {
Self::new()
}
}