diff options
Diffstat (limited to 'library/std/src/sys/xous/locks/rwlock.rs')
-rw-r--r-- | library/std/src/sys/xous/locks/rwlock.rs | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/library/std/src/sys/xous/locks/rwlock.rs b/library/std/src/sys/xous/locks/rwlock.rs new file mode 100644 index 000000000..618da758a --- /dev/null +++ b/library/std/src/sys/xous/locks/rwlock.rs @@ -0,0 +1,72 @@ +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)); + } +} |