use core::sync::atomic::{AtomicBool, Ordering};
use crate::WaitQueue;
pub struct IrqNotify {
pending: AtomicBool,
wait: WaitQueue,
}
impl Default for IrqNotify {
fn default() -> Self {
Self::new()
}
}
impl IrqNotify {
pub const fn new() -> Self {
Self {
pending: AtomicBool::new(false),
wait: WaitQueue::new(),
}
}
pub fn notify_irq(&self) {
self.pending.store(true, Ordering::Release);
self.wait.notify_one_from_irq();
}
pub fn notify(&self) {
self.pending.store(true, Ordering::Release);
self.wait.notify_one(true);
}
pub fn is_pending(&self) -> bool {
self.pending.load(Ordering::Acquire)
}
pub fn drain(&self) -> bool {
self.pending.swap(false, Ordering::AcqRel)
}
#[track_caller]
pub fn wait(&self) {
self.wait.wait_until(|| self.drain());
}
#[track_caller]
pub fn wait_timeout(&self, duration: core::time::Duration) -> bool {
self.wait.wait_timeout_until(duration, || self.drain())
}
}
#[cfg(test)]
mod coverage_tests {
use super::*;
fn irq_notify_constructor_and_pending_hold_for_test() -> bool {
let notify = IrqNotify::new();
assert!(!notify.is_pending());
let default_notify = IrqNotify::default();
assert!(!default_notify.is_pending());
true
}
fn irq_notify_drain_logic_hold_for_test() -> bool {
let notify = IrqNotify::new();
assert!(!notify.drain()); assert!(!notify.is_pending());
true
}
#[test]
fn irq_notify_constructor_and_pending_hold() {
assert!(irq_notify_constructor_and_pending_hold_for_test());
}
#[test]
fn irq_notify_drain_logic_hold() {
assert!(irq_notify_drain_logic_hold_for_test());
}
}