use crate::os::xous::ffi::do_yield; use crate::sync::atomic::{AtomicIsize, Ordering::SeqCst}; pub struct RwLock { /// The "mode" value indicates how many threads are waiting on this /// Mutex. Possible values are: /// -1: The lock is locked for writing /// 0: The lock is unlocked /// >=1: The lock is locked for reading /// /// This currently spins waiting for the lock to be freed. An /// optimization would be to involve the ticktimer server to /// coordinate unlocks. mode: AtomicIsize, } unsafe impl Send for RwLock {} unsafe impl Sync for RwLock {} impl RwLock { #[inline] #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] pub const fn new() -> RwLock { RwLock { mode: AtomicIsize::new(0) } } #[inline] pub unsafe fn read(&self) { while !unsafe { self.try_read() } { do_yield(); } } #[inline] pub unsafe fn try_read(&self) -> bool { // Non-atomically determine the current value. let current = self.mode.load(SeqCst); // If it's currently locked for writing, then we cannot read. if current < 0 { return false; } // Attempt to lock. If the `current` value has changed, then this // operation will fail and we will not obtain the lock even if we // could potentially keep it. let new = current + 1; self.mode.compare_exchange(current, new, SeqCst, SeqCst).is_ok() } #[inline] pub unsafe fn write(&self) { while !unsafe { self.try_write() } { do_yield(); } } #[inline] pub unsafe fn try_write(&self) -> bool { self.mode.compare_exchange(0, -1, SeqCst, SeqCst).is_ok() } #[inline] pub unsafe fn read_unlock(&self) { self.mode.fetch_sub(1, SeqCst); } #[inline] pub unsafe fn write_unlock(&self) { assert_eq!(self.mode.compare_exchange(-1, 0, SeqCst, SeqCst), Ok(-1)); } }