use super::mutex::Mutex; use crate::os::xous::ffi::{blocking_scalar, scalar}; use crate::os::xous::services::ticktimer_server; use crate::sync::Mutex as StdMutex; use crate::time::Duration; // The implementation is inspired by Andrew D. Birrell's paper // "Implementing Condition Variables with Semaphores" pub struct Condvar { counter: StdMutex, } unsafe impl Send for Condvar {} unsafe impl Sync for Condvar {} impl Condvar { #[inline] #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] pub const fn new() -> Condvar { Condvar { counter: StdMutex::new(0) } } pub fn notify_one(&self) { let mut counter = self.counter.lock().unwrap(); if *counter <= 0 { return; } else { *counter -= 1; } let result = blocking_scalar( ticktimer_server(), crate::os::xous::services::TicktimerScalar::NotifyCondition(self.index(), 1).into(), ); drop(counter); result.expect("failure to send NotifyCondition command"); } pub fn notify_all(&self) { let mut counter = self.counter.lock().unwrap(); if *counter <= 0 { return; } let result = blocking_scalar( ticktimer_server(), crate::os::xous::services::TicktimerScalar::NotifyCondition(self.index(), *counter) .into(), ); *counter = 0; drop(counter); result.expect("failure to send NotifyCondition command"); } fn index(&self) -> usize { self as *const Condvar as usize } pub unsafe fn wait(&self, mutex: &Mutex) { let mut counter = self.counter.lock().unwrap(); *counter += 1; unsafe { mutex.unlock() }; drop(counter); let result = blocking_scalar( ticktimer_server(), crate::os::xous::services::TicktimerScalar::WaitForCondition(self.index(), 0).into(), ); unsafe { mutex.lock() }; result.expect("Ticktimer: failure to send WaitForCondition command"); } pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { let mut counter = self.counter.lock().unwrap(); *counter += 1; unsafe { mutex.unlock() }; drop(counter); let mut millis = dur.as_millis() as usize; if millis == 0 { millis = 1; } let result = blocking_scalar( ticktimer_server(), crate::os::xous::services::TicktimerScalar::WaitForCondition(self.index(), millis) .into(), ); unsafe { mutex.lock() }; let result = result.expect("Ticktimer: failure to send WaitForCondition command")[0] == 0; // If we awoke due to a timeout, decrement the wake count, as that would not have // been done in the `notify()` call. if !result { *self.counter.lock().unwrap() -= 1; } result } } impl Drop for Condvar { fn drop(&mut self) { scalar( ticktimer_server(), crate::os::xous::services::TicktimerScalar::FreeCondition(self.index()).into(), ) .ok(); } }