summaryrefslogtreecommitdiffstats
path: root/library/std/src/sys/xous/locks/rwlock.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys/xous/locks/rwlock.rs')
-rw-r--r--library/std/src/sys/xous/locks/rwlock.rs72
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));
+ }
+}