use std::sync::atomic::*;
use std::sync::{Condvar, Mutex};
pub struct Signal {
lock: Mutex<()>,
condvar: Condvar,
notified: AtomicBool,
waiting: AtomicUsize,
}
impl Default for Signal {
fn default() -> Self {
Self {
lock: Mutex::new(()),
condvar: Condvar::new(),
notified: AtomicBool::default(),
waiting: AtomicUsize::default(),
}
}
}
impl Signal {
pub fn notify(&self) {
self.notified.store(true, Ordering::SeqCst);
if self.waiting.load(Ordering::SeqCst) > 0 {
let _guard = self.lock.lock().unwrap();
self.condvar.notify_one();
}
}
pub fn wait(&self) {
if self.notified.swap(false, Ordering::SeqCst) {
return;
}
self.waiting.fetch_add(1, Ordering::SeqCst);
let mut guard = self.lock.lock().unwrap();
while !self.notified.swap(false, Ordering::SeqCst) {
guard = self.condvar.wait(guard).unwrap();
}
drop(guard);
self.waiting.fetch_sub(1, Ordering::SeqCst);
}
}