aboutsummaryrefslogtreecommitdiff
path: root/embassy-sync/src
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-sync/src')
-rw-r--r--embassy-sync/src/blocking_rwlock/mod.rs221
-rw-r--r--embassy-sync/src/blocking_rwlock/raw.rs209
-rw-r--r--embassy-sync/src/lib.rs1
-rw-r--r--embassy-sync/src/rwlock.rs157
4 files changed, 52 insertions, 536 deletions
diff --git a/embassy-sync/src/blocking_rwlock/mod.rs b/embassy-sync/src/blocking_rwlock/mod.rs
deleted file mode 100644
index 88cd2164b..000000000
--- a/embassy-sync/src/blocking_rwlock/mod.rs
+++ /dev/null
@@ -1,221 +0,0 @@
1//! Blocking read-write lock.
2//!
3//! This module provides a blocking read-write lock that can be used to synchronize data.
4pub mod raw;
5
6use core::cell::UnsafeCell;
7
8use self::raw::RawRwLock;
9
10/// Blocking read-write lock (not async)
11///
12/// Provides a blocking read-write lock primitive backed by an implementation of [`raw::RawRwLock`].
13///
14/// Which implementation you select depends on the context in which you're using the read-write lock, and you can choose which kind
15/// of interior mutability fits your use case.
16///
17/// Use [`CriticalSectionRwLock`] when data can be shared between threads and interrupts.
18///
19/// Use [`NoopRwLock`] when data is only shared between tasks running on the same executor.
20///
21/// Use [`ThreadModeRwLock`] when data is shared between tasks running on the same executor but you want a global singleton.
22///
23/// In all cases, the blocking read-write lock is intended to be short lived and not held across await points.
24/// Use the async [`RwLock`](crate::rwlock::RwLock) if you need a lock that is held across await points.
25pub struct RwLock<R, T: ?Sized> {
26 // NOTE: `raw` must be FIRST, so when using ThreadModeRwLock the "can't drop in non-thread-mode" gets
27 // to run BEFORE dropping `data`.
28 raw: R,
29 data: UnsafeCell<T>,
30}
31
32unsafe impl<R: RawRwLock + Send, T: ?Sized + Send> Send for RwLock<R, T> {}
33unsafe impl<R: RawRwLock + Sync, T: ?Sized + Send> Sync for RwLock<R, T> {}
34
35impl<R: RawRwLock, T> RwLock<R, T> {
36 /// Creates a new read-write lock in an unlocked state ready for use.
37 #[inline]
38 pub const fn new(val: T) -> RwLock<R, T> {
39 RwLock {
40 raw: R::INIT,
41 data: UnsafeCell::new(val),
42 }
43 }
44
45 /// Creates a critical section and grants temporary read access to the protected data.
46 pub fn read_lock<U>(&self, f: impl FnOnce(&T) -> U) -> U {
47 self.raw.read_lock(|| {
48 let ptr = self.data.get() as *const T;
49 let inner = unsafe { &*ptr };
50 f(inner)
51 })
52 }
53
54 /// Creates a critical section and grants temporary write access to the protected data.
55 pub fn write_lock<U>(&self, f: impl FnOnce(&mut T) -> U) -> U {
56 self.raw.write_lock(|| {
57 let ptr = self.data.get() as *mut T;
58 let inner = unsafe { &mut *ptr };
59 f(inner)
60 })
61 }
62}
63
64impl<R, T> RwLock<R, T> {
65 /// Creates a new read-write lock based on a pre-existing raw read-write lock.
66 ///
67 /// This allows creating a read-write lock in a constant context on stable Rust.
68 #[inline]
69 pub const fn const_new(raw_rwlock: R, val: T) -> RwLock<R, T> {
70 RwLock {
71 raw: raw_rwlock,
72 data: UnsafeCell::new(val),
73 }
74 }
75
76 /// Consumes this read-write lock, returning the underlying data.
77 #[inline]
78 pub fn into_inner(self) -> T {
79 self.data.into_inner()
80 }
81
82 /// Returns a mutable reference to the underlying data.
83 ///
84 /// Since this call borrows the `RwLock` mutably, no actual locking needs to
85 /// take place---the mutable borrow statically guarantees no locks exist.
86 #[inline]
87 pub fn get_mut(&mut self) -> &mut T {
88 unsafe { &mut *self.data.get() }
89 }
90}
91
92/// A read-write lock that allows borrowing data across executors and interrupts.
93///
94/// # Safety
95///
96/// This read-write lock is safe to share between different executors and interrupts.
97pub type CriticalSectionRwLock<T> = RwLock<raw::CriticalSectionRawRwLock, T>;
98
99/// A read-write lock that allows borrowing data in the context of a single executor.
100///
101/// # Safety
102///
103/// **This Read-Write Lock is only safe within a single executor.**
104pub type NoopRwLock<T> = RwLock<raw::NoopRawRwLock, T>;
105
106impl<T> RwLock<raw::CriticalSectionRawRwLock, T> {
107 /// Borrows the data for the duration of the critical section
108 pub fn borrow<'cs>(&'cs self, _cs: critical_section::CriticalSection<'cs>) -> &'cs T {
109 let ptr = self.data.get() as *const T;
110 unsafe { &*ptr }
111 }
112}
113
114impl<T> RwLock<raw::NoopRawRwLock, T> {
115 /// Borrows the data
116 #[allow(clippy::should_implement_trait)]
117 pub fn borrow(&self) -> &T {
118 let ptr = self.data.get() as *const T;
119 unsafe { &*ptr }
120 }
121}
122
123// ThreadModeRwLock does NOT use the generic read-write lock from above because it's special:
124// it's Send+Sync even if T: !Send. There's no way to do that without specialization (I think?).
125//
126// There's still a ThreadModeRawRwLock for use with the generic RwLock (handy with Channel, for example),
127// but that will require T: Send even though it shouldn't be needed.
128
129#[cfg(any(cortex_m, feature = "std"))]
130pub use thread_mode_rwlock::*;
131#[cfg(any(cortex_m, feature = "std"))]
132mod thread_mode_rwlock {
133 use super::*;
134
135 /// A "read-write lock" that only allows borrowing from thread mode.
136 ///
137 /// # Safety
138 ///
139 /// **This Read-Write Lock is only safe on single-core systems.**
140 ///
141 /// On multi-core systems, a `ThreadModeRwLock` **is not sufficient** to ensure exclusive access.
142 pub struct ThreadModeRwLock<T: ?Sized> {
143 inner: UnsafeCell<T>,
144 }
145
146 // NOTE: ThreadModeRwLock only allows borrowing from one execution context ever: thread mode.
147 // Therefore it cannot be used to send non-sendable stuff between execution contexts, so it can
148 // be Send+Sync even if T is not Send (unlike CriticalSectionRwLock)
149 unsafe impl<T: ?Sized> Sync for ThreadModeRwLock<T> {}
150 unsafe impl<T: ?Sized> Send for ThreadModeRwLock<T> {}
151
152 impl<T> ThreadModeRwLock<T> {
153 /// Creates a new read-write lock
154 pub const fn new(value: T) -> Self {
155 ThreadModeRwLock {
156 inner: UnsafeCell::new(value),
157 }
158 }
159 }
160
161 impl<T: ?Sized> ThreadModeRwLock<T> {
162 /// Lock the `ThreadModeRwLock` for reading, granting access to the data.
163 ///
164 /// # Panics
165 ///
166 /// This will panic if not currently running in thread mode.
167 pub fn read_lock<R>(&self, f: impl FnOnce(&T) -> R) -> R {
168 f(self.borrow())
169 }
170
171 /// Lock the `ThreadModeRwLock` for writing, granting access to the data.
172 ///
173 /// # Panics
174 ///
175 /// This will panic if not currently running in thread mode.
176 pub fn write_lock<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
177 f(self.borrow_mut())
178 }
179
180 /// Borrows the data
181 ///
182 /// # Panics
183 ///
184 /// This will panic if not currently running in thread mode.
185 pub fn borrow(&self) -> &T {
186 assert!(
187 raw::in_thread_mode(),
188 "ThreadModeRwLock can only be borrowed from thread mode."
189 );
190 unsafe { &*self.inner.get() }
191 }
192
193 /// Mutably borrows the data
194 ///
195 /// # Panics
196 ///
197 /// This will panic if not currently running in thread mode.
198 pub fn borrow_mut(&self) -> &mut T {
199 assert!(
200 raw::in_thread_mode(),
201 "ThreadModeRwLock can only be borrowed from thread mode."
202 );
203 unsafe { &mut *self.inner.get() }
204 }
205 }
206
207 impl<T: ?Sized> Drop for ThreadModeRwLock<T> {
208 fn drop(&mut self) {
209 // Only allow dropping from thread mode. Dropping calls drop on the inner `T`, so
210 // `drop` needs the same guarantees as `lock`. `ThreadModeRwLock<T>` is Send even if
211 // T isn't, so without this check a user could create a ThreadModeRwLock in thread mode,
212 // send it to interrupt context and drop it there, which would "send" a T even if T is not Send.
213 assert!(
214 raw::in_thread_mode(),
215 "ThreadModeRwLock can only be dropped from thread mode."
216 );
217
218 // Drop of the inner `T` happens after this.
219 }
220 }
221}
diff --git a/embassy-sync/src/blocking_rwlock/raw.rs b/embassy-sync/src/blocking_rwlock/raw.rs
deleted file mode 100644
index 2fb9ce9d1..000000000
--- a/embassy-sync/src/blocking_rwlock/raw.rs
+++ /dev/null
@@ -1,209 +0,0 @@
1//! Read-Write Lock primitives.
2//!
3//! This module provides a trait for read-write locks that can be used in different contexts.
4use core::cell::RefCell;
5use core::marker::PhantomData;
6
7/// Raw read-write lock trait.
8///
9/// This read-write lock is "raw", which means it does not actually contain the protected data, it
10/// just implements the read-write lock mechanism. For most uses you should use [`super::RwLock`] instead,
11/// which is generic over a RawRwLock and contains the protected data.
12///
13/// Note that, unlike other read-write locks, implementations only guarantee no
14/// concurrent access from other threads: concurrent access from the current
15/// thread is allowed. For example, it's possible to lock the same read-write lock multiple times reentrantly.
16///
17/// Therefore, locking a `RawRwLock` is only enough to guarantee safe shared (`&`) access
18/// to the data, it is not enough to guarantee exclusive (`&mut`) access.
19///
20/// # Safety
21///
22/// RawRwLock implementations must ensure that, while locked, no other thread can lock
23/// the RawRwLock concurrently.
24///
25/// Unsafe code is allowed to rely on this fact, so incorrect implementations will cause undefined behavior.
26pub unsafe trait RawRwLock {
27 /// Create a new `RawRwLock` instance.
28 ///
29 /// This is a const instead of a method to allow creating instances in const context.
30 const INIT: Self;
31
32 /// Lock this `RawRwLock` for reading.
33 fn read_lock<R>(&self, f: impl FnOnce() -> R) -> R;
34
35 /// Lock this `RawRwLock` for writing.
36 fn write_lock<R>(&self, f: impl FnOnce() -> R) -> R;
37}
38
39/// A read-write lock that allows borrowing data across executors and interrupts.
40///
41/// # Safety
42///
43/// This read-write lock is safe to share between different executors and interrupts.
44pub struct CriticalSectionRawRwLock {
45 state: RefCell<isize>,
46}
47
48unsafe impl Send for CriticalSectionRawRwLock {}
49unsafe impl Sync for CriticalSectionRawRwLock {}
50
51impl CriticalSectionRawRwLock {
52 /// Creates a new [`CriticalSectionRawRwLock`].
53 pub const fn new() -> Self {
54 Self { state: RefCell::new(0) }
55 }
56
57 fn lock_read(&self) {
58 critical_section::with(|_| {
59 let mut state = self.state.borrow_mut();
60
61 while *state & WRITER != 0 {
62 // Spin until the writer releases the lock
63 }
64 *state += 1;
65 });
66 }
67
68 fn unlock_read(&self) {
69 critical_section::with(|_| {
70 *self.state.borrow_mut() -= 1;
71 });
72 }
73
74 fn lock_write(&self) {
75 critical_section::with(|_| {
76 let mut state = self.state.borrow_mut();
77
78 while *state != 0 {
79 // Spin until all readers and writers release the lock
80 }
81 *state = WRITER;
82 });
83 }
84
85 fn unlock_write(&self) {
86 critical_section::with(|_| {
87 *self.state.borrow_mut() = 0;
88 });
89 }
90}
91
92unsafe impl RawRwLock for CriticalSectionRawRwLock {
93 const INIT: Self = Self::new();
94
95 fn read_lock<R>(&self, f: impl FnOnce() -> R) -> R {
96 self.lock_read();
97 let result = f();
98 self.unlock_read();
99 result
100 }
101
102 fn write_lock<R>(&self, f: impl FnOnce() -> R) -> R {
103 self.lock_write();
104 let result = f();
105 self.unlock_write();
106 result
107 }
108}
109
110const WRITER: isize = -1;
111
112// ================
113
114/// A read-write lock that allows borrowing data in the context of a single executor.
115///
116/// # Safety
117///
118/// **This Read-Write Lock is only safe within a single executor.**
119pub struct NoopRawRwLock {
120 _phantom: PhantomData<*mut ()>,
121}
122
123unsafe impl Send for NoopRawRwLock {}
124
125impl NoopRawRwLock {
126 /// Create a new `NoopRawRwLock`.
127 pub const fn new() -> Self {
128 Self { _phantom: PhantomData }
129 }
130}
131
132unsafe impl RawRwLock for NoopRawRwLock {
133 const INIT: Self = Self::new();
134 fn read_lock<R>(&self, f: impl FnOnce() -> R) -> R {
135 f()
136 }
137
138 fn write_lock<R>(&self, f: impl FnOnce() -> R) -> R {
139 f()
140 }
141}
142
143// ================
144
145#[cfg(any(cortex_m, feature = "std"))]
146mod thread_mode {
147 use super::*;
148
149 /// A "read-write lock" that only allows borrowing from thread mode.
150 ///
151 /// # Safety
152 ///
153 /// **This Read-Write Lock is only safe on single-core systems.**
154 ///
155 /// On multi-core systems, a `ThreadModeRawRwLock` **is not sufficient** to ensure exclusive access.
156 pub struct ThreadModeRawRwLock {
157 _phantom: PhantomData<()>,
158 }
159
160 unsafe impl Send for ThreadModeRawRwLock {}
161 unsafe impl Sync for ThreadModeRawRwLock {}
162
163 impl ThreadModeRawRwLock {
164 /// Create a new `ThreadModeRawRwLock`.
165 pub const fn new() -> Self {
166 Self { _phantom: PhantomData }
167 }
168 }
169
170 unsafe impl RawRwLock for ThreadModeRawRwLock {
171 const INIT: Self = Self::new();
172 fn read_lock<R>(&self, f: impl FnOnce() -> R) -> R {
173 assert!(
174 in_thread_mode(),
175 "ThreadModeRwLock can only be locked from thread mode."
176 );
177
178 f()
179 }
180
181 fn write_lock<R>(&self, f: impl FnOnce() -> R) -> R {
182 assert!(
183 in_thread_mode(),
184 "ThreadModeRwLock can only be locked from thread mode."
185 );
186
187 f()
188 }
189 }
190
191 impl Drop for ThreadModeRawRwLock {
192 fn drop(&mut self) {
193 assert!(
194 in_thread_mode(),
195 "ThreadModeRwLock can only be dropped from thread mode."
196 );
197 }
198 }
199
200 pub(crate) fn in_thread_mode() -> bool {
201 #[cfg(feature = "std")]
202 return Some("main") == std::thread::current().name();
203
204 #[cfg(not(feature = "std"))]
205 return unsafe { (0xE000ED04 as *const u32).read_volatile() } & 0x1FF == 0;
206 }
207}
208#[cfg(any(cortex_m, feature = "std"))]
209pub use thread_mode::*;
diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs
index b9ead5f79..5d91b4d9c 100644
--- a/embassy-sync/src/lib.rs
+++ b/embassy-sync/src/lib.rs
@@ -11,7 +11,6 @@ pub(crate) mod fmt;
11mod ring_buffer; 11mod ring_buffer;
12 12
13pub mod blocking_mutex; 13pub mod blocking_mutex;
14pub mod blocking_rwlock;
15pub mod channel; 14pub mod channel;
16pub mod lazy_lock; 15pub mod lazy_lock;
17pub mod mutex; 16pub mod mutex;
diff --git a/embassy-sync/src/rwlock.rs b/embassy-sync/src/rwlock.rs
index 0ad5d5864..0e4088c1e 100644
--- a/embassy-sync/src/rwlock.rs
+++ b/embassy-sync/src/rwlock.rs
@@ -7,8 +7,8 @@ use core::future::{poll_fn, Future};
7use core::ops::{Deref, DerefMut}; 7use core::ops::{Deref, DerefMut};
8use core::task::Poll; 8use core::task::Poll;
9 9
10use crate::blocking_rwlock::raw::RawRwLock; 10use crate::blocking_mutex::raw::RawMutex;
11use crate::blocking_rwlock::RwLock as BlockingRwLock; 11use crate::blocking_mutex::Mutex as BlockingMutex;
12use crate::waitqueue::WakerRegistration; 12use crate::waitqueue::WakerRegistration;
13 13
14/// Error returned by [`RwLock::try_read_lock`] and [`RwLock::try_write_lock`] 14/// Error returned by [`RwLock::try_read_lock`] and [`RwLock::try_write_lock`]
@@ -31,53 +31,48 @@ struct State {
31/// 31///
32/// Which implementation you select depends on the context in which you're using the read-write lock. 32/// Which implementation you select depends on the context in which you're using the read-write lock.
33/// 33///
34/// Use [`CriticalSectionRawRwLock`](crate::blocking_mutex::raw_rwlock::CriticalSectionRawRwLock) when data can be shared between threads and interrupts. 34/// Use [`CriticalSectionMutex`] when data can be shared between threads and interrupts.
35/// 35///
36/// Use [`NoopRawRwLock`](crate::blocking_mutex::raw_rwlock::NoopRawRwLock) when data is only shared between tasks running on the same executor. 36/// Use [`NoopMutex`] when data is only shared between tasks running on the same executor.
37/// 37///
38/// Use [`ThreadModeRawRwLock`](crate::blocking_mutex::raw_rwlock::ThreadModeRawRwLock) when data is shared between tasks running on the same executor but you want a singleton. 38/// Use [`ThreadModeMutex`] when data is shared between tasks running on the same executor but you want a global singleton.
39/// 39///
40pub struct RwLock<R, T> 40
41pub struct RwLock<M, T>
41where 42where
42 R: RawRwLock, 43 M: RawMutex,
43 T: ?Sized, 44 T: ?Sized,
44{ 45{
45 state: BlockingRwLock<R, RefCell<State>>, 46 state: BlockingMutex<M, RefCell<State>>,
46 inner: UnsafeCell<T>, 47 inner: UnsafeCell<T>,
47} 48}
48 49
49unsafe impl<R: RawRwLock + Send, T: ?Sized + Send> Send for RwLock<R, T> {} 50unsafe impl<M: RawMutex + Send, T: ?Sized + Send> Send for RwLock<M, T> {}
50unsafe impl<R: RawRwLock + Sync, T: ?Sized + Send> Sync for RwLock<R, T> {} 51unsafe impl<M: RawMutex + Sync, T: ?Sized + Send> Sync for RwLock<M, T> {}
51 52
52/// Async read-write lock. 53/// Async read-write lock.
53impl<R, T> RwLock<R, T> 54impl<R, T> RwLock<R, T>
54where 55where
55 R: RawRwLock, 56 R: RawMutex,
56{ 57{
57 /// Create a new read-write lock with the given value. 58 /// Create a new read-write lock with the given value.
58 pub const fn new(value: T) -> Self { 59 pub const fn new(value: T) -> Self {
59 Self { 60 Self {
60 inner: UnsafeCell::new(value), 61 inner: UnsafeCell::new(value),
61 state: BlockingRwLock::new(RefCell::new(State { 62 state: BlockingMutex::new(RefCell::new(State {
62 readers: 0, 63 readers: 0,
63 writer: false, 64 writer: false,
64 waker: WakerRegistration::new(), 65 waker: WakerRegistration::new(),
65 })), 66 })),
66 } 67 }
67 } 68 }
68}
69 69
70impl<R, T> RwLock<R, T>
71where
72 R: RawRwLock,
73 T: ?Sized,
74{
75 /// Lock the read-write lock for reading. 70 /// Lock the read-write lock for reading.
76 /// 71 ///
77 /// This will wait for the lock to be available if it's already locked for writing. 72 /// This will wait for the lock to be available if it's already locked for writing.
78 pub fn read_lock(&self) -> impl Future<Output = RwLockReadGuard<'_, R, T>> { 73 pub fn read(&self) -> impl Future<Output = RwLockReadGuard<'_, R, T>> {
79 poll_fn(|cx| { 74 poll_fn(|cx| {
80 let ready = self.state.write_lock(|s| { 75 let ready = self.state.lock(|s| {
81 let mut s = s.borrow_mut(); 76 let mut s = s.borrow_mut();
82 if s.writer { 77 if s.writer {
83 s.waker.register(cx.waker()); 78 s.waker.register(cx.waker());
@@ -99,11 +94,11 @@ where
99 /// Lock the read-write lock for writing. 94 /// Lock the read-write lock for writing.
100 /// 95 ///
101 /// This will wait for the lock to be available if it's already locked for reading or writing. 96 /// This will wait for the lock to be available if it's already locked for reading or writing.
102 pub fn write_lock(&self) -> impl Future<Output = RwLockWriteGuard<'_, R, T>> { 97 pub fn write(&self) -> impl Future<Output = RwLockWriteGuard<'_, R, T>> {
103 poll_fn(|cx| { 98 poll_fn(|cx| {
104 let ready = self.state.write_lock(|s| { 99 let ready = self.state.lock(|s| {
105 let mut s = s.borrow_mut(); 100 let mut s = s.borrow_mut();
106 if s.readers > 0 || s.writer { 101 if s.writer || s.readers > 0 {
107 s.waker.register(cx.waker()); 102 s.waker.register(cx.waker());
108 false 103 false
109 } else { 104 } else {
@@ -119,41 +114,13 @@ where
119 } 114 }
120 }) 115 })
121 } 116 }
117}
122 118
123 /// Attempt to immediately lock the read-write lock for reading. 119impl<R, T> RwLock<R, T>
124 /// 120where
125 /// If the lock is already locked for writing, this will return an error instead of waiting. 121 R: RawMutex,
126 pub fn try_read_lock(&self) -> Result<RwLockReadGuard<'_, R, T>, TryLockError> { 122 T: ?Sized,
127 self.state.read_lock(|s| { 123{
128 let mut s = s.borrow_mut();
129 if s.writer {
130 Err(TryLockError)
131 } else {
132 s.readers += 1;
133 Ok(())
134 }
135 })?;
136
137 Ok(RwLockReadGuard { rwlock: self })
138 }
139
140 /// Attempt to immediately lock the read-write lock for writing.
141 ///
142 /// If the lock is already locked for reading or writing, this will return an error instead of waiting.
143 pub fn try_write_lock(&self) -> Result<RwLockWriteGuard<'_, R, T>, TryLockError> {
144 self.state.write_lock(|s| {
145 let mut s = s.borrow_mut();
146 if s.readers > 0 || s.writer {
147 Err(TryLockError)
148 } else {
149 s.writer = true;
150 Ok(())
151 }
152 })?;
153
154 Ok(RwLockWriteGuard { rwlock: self })
155 }
156
157 /// Consumes this read-write lock, returning the underlying data. 124 /// Consumes this read-write lock, returning the underlying data.
158 pub fn into_inner(self) -> T 125 pub fn into_inner(self) -> T
159 where 126 where
@@ -171,7 +138,7 @@ where
171 } 138 }
172} 139}
173 140
174impl<R: RawRwLock, T> From<T> for RwLock<R, T> { 141impl<R: RawMutex, T> From<T> for RwLock<R, T> {
175 fn from(from: T) -> Self { 142 fn from(from: T) -> Self {
176 Self::new(from) 143 Self::new(from)
177 } 144 }
@@ -179,7 +146,7 @@ impl<R: RawRwLock, T> From<T> for RwLock<R, T> {
179 146
180impl<R, T> Default for RwLock<R, T> 147impl<R, T> Default for RwLock<R, T>
181where 148where
182 R: RawRwLock, 149 R: RawMutex,
183 T: Default, 150 T: Default,
184{ 151{
185 fn default() -> Self { 152 fn default() -> Self {
@@ -187,26 +154,6 @@ where
187 } 154 }
188} 155}
189 156
190impl<R, T> fmt::Debug for RwLock<R, T>
191where
192 R: RawRwLock,
193 T: ?Sized + fmt::Debug,
194{
195 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196 let mut d = f.debug_struct("RwLock");
197 match self.try_write_lock() {
198 Ok(value) => {
199 d.field("inner", &&*value);
200 }
201 Err(TryLockError) => {
202 d.field("inner", &format_args!("<locked>"));
203 }
204 }
205
206 d.finish_non_exhaustive()
207 }
208}
209
210/// Async read lock guard. 157/// Async read lock guard.
211/// 158///
212/// Owning an instance of this type indicates having 159/// Owning an instance of this type indicates having
@@ -217,19 +164,19 @@ where
217#[must_use = "if unused the RwLock will immediately unlock"] 164#[must_use = "if unused the RwLock will immediately unlock"]
218pub struct RwLockReadGuard<'a, R, T> 165pub struct RwLockReadGuard<'a, R, T>
219where 166where
220 R: RawRwLock, 167 R: RawMutex,
221 T: ?Sized, 168 T: ?Sized,
222{ 169{
223 rwlock: &'a RwLock<R, T>, 170 rwlock: &'a RwLock<R, T>,
224} 171}
225 172
226impl<'a, R, T> Drop for RwLockReadGuard<'a, R, T> 173impl<'a, M, T> Drop for RwLockReadGuard<'a, M, T>
227where 174where
228 R: RawRwLock, 175 M: RawMutex,
229 T: ?Sized, 176 T: ?Sized,
230{ 177{
231 fn drop(&mut self) { 178 fn drop(&mut self) {
232 self.rwlock.state.write_lock(|s| { 179 self.rwlock.state.lock(|s| {
233 let mut s = unwrap!(s.try_borrow_mut()); 180 let mut s = unwrap!(s.try_borrow_mut());
234 s.readers -= 1; 181 s.readers -= 1;
235 if s.readers == 0 { 182 if s.readers == 0 {
@@ -239,9 +186,9 @@ where
239 } 186 }
240} 187}
241 188
242impl<'a, R, T> Deref for RwLockReadGuard<'a, R, T> 189impl<'a, M, T> Deref for RwLockReadGuard<'a, M, T>
243where 190where
244 R: RawRwLock, 191 M: RawMutex,
245 T: ?Sized, 192 T: ?Sized,
246{ 193{
247 type Target = T; 194 type Target = T;
@@ -252,9 +199,9 @@ where
252 } 199 }
253} 200}
254 201
255impl<'a, R, T> fmt::Debug for RwLockReadGuard<'a, R, T> 202impl<'a, M, T> fmt::Debug for RwLockReadGuard<'a, M, T>
256where 203where
257 R: RawRwLock, 204 M: RawMutex,
258 T: ?Sized + fmt::Debug, 205 T: ?Sized + fmt::Debug,
259{ 206{
260 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -262,9 +209,9 @@ where
262 } 209 }
263} 210}
264 211
265impl<'a, R, T> fmt::Display for RwLockReadGuard<'a, R, T> 212impl<'a, M, T> fmt::Display for RwLockReadGuard<'a, M, T>
266where 213where
267 R: RawRwLock, 214 M: RawMutex,
268 T: ?Sized + fmt::Display, 215 T: ?Sized + fmt::Display,
269{ 216{
270 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 217 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -282,7 +229,7 @@ where
282#[must_use = "if unused the RwLock will immediately unlock"] 229#[must_use = "if unused the RwLock will immediately unlock"]
283pub struct RwLockWriteGuard<'a, R, T> 230pub struct RwLockWriteGuard<'a, R, T>
284where 231where
285 R: RawRwLock, 232 R: RawMutex,
286 T: ?Sized, 233 T: ?Sized,
287{ 234{
288 rwlock: &'a RwLock<R, T>, 235 rwlock: &'a RwLock<R, T>,
@@ -290,11 +237,11 @@ where
290 237
291impl<'a, R, T> Drop for RwLockWriteGuard<'a, R, T> 238impl<'a, R, T> Drop for RwLockWriteGuard<'a, R, T>
292where 239where
293 R: RawRwLock, 240 R: RawMutex,
294 T: ?Sized, 241 T: ?Sized,
295{ 242{
296 fn drop(&mut self) { 243 fn drop(&mut self) {
297 self.rwlock.state.write_lock(|s| { 244 self.rwlock.state.lock(|s| {
298 let mut s = unwrap!(s.try_borrow_mut()); 245 let mut s = unwrap!(s.try_borrow_mut());
299 s.writer = false; 246 s.writer = false;
300 s.waker.wake(); 247 s.waker.wake();
@@ -304,7 +251,7 @@ where
304 251
305impl<'a, R, T> Deref for RwLockWriteGuard<'a, R, T> 252impl<'a, R, T> Deref for RwLockWriteGuard<'a, R, T>
306where 253where
307 R: RawRwLock, 254 R: RawMutex,
308 T: ?Sized, 255 T: ?Sized,
309{ 256{
310 type Target = T; 257 type Target = T;
@@ -317,7 +264,7 @@ where
317 264
318impl<'a, R, T> DerefMut for RwLockWriteGuard<'a, R, T> 265impl<'a, R, T> DerefMut for RwLockWriteGuard<'a, R, T>
319where 266where
320 R: RawRwLock, 267 R: RawMutex,
321 T: ?Sized, 268 T: ?Sized,
322{ 269{
323 fn deref_mut(&mut self) -> &mut Self::Target { 270 fn deref_mut(&mut self) -> &mut Self::Target {
@@ -329,7 +276,7 @@ where
329 276
330impl<'a, R, T> fmt::Debug for RwLockWriteGuard<'a, R, T> 277impl<'a, R, T> fmt::Debug for RwLockWriteGuard<'a, R, T>
331where 278where
332 R: RawRwLock, 279 R: RawMutex,
333 T: ?Sized + fmt::Debug, 280 T: ?Sized + fmt::Debug,
334{ 281{
335 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 282 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -339,7 +286,7 @@ where
339 286
340impl<'a, R, T> fmt::Display for RwLockWriteGuard<'a, R, T> 287impl<'a, R, T> fmt::Display for RwLockWriteGuard<'a, R, T>
341where 288where
342 R: RawRwLock, 289 R: RawMutex,
343 T: ?Sized + fmt::Display, 290 T: ?Sized + fmt::Display,
344{ 291{
345 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 292 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -349,41 +296,41 @@ where
349 296
350#[cfg(test)] 297#[cfg(test)]
351mod tests { 298mod tests {
352 use crate::blocking_rwlock::raw::NoopRawRwLock; 299 use crate::blocking_mutex::raw::NoopRawMutex;
353 use crate::rwlock::RwLock; 300 use crate::rwlock::RwLock;
354 301
355 #[futures_test::test] 302 #[futures_test::test]
356 async fn read_guard_releases_lock_when_dropped() { 303 async fn read_guard_releases_lock_when_dropped() {
357 let rwlock: RwLock<NoopRawRwLock, [i32; 2]> = RwLock::new([0, 1]); 304 let rwlock: RwLock<NoopRawMutex, [i32; 2]> = RwLock::new([0, 1]);
358 305
359 { 306 {
360 let guard = rwlock.read_lock().await; 307 let guard = rwlock.read().await;
361 assert_eq!(*guard, [0, 1]); 308 assert_eq!(*guard, [0, 1]);
362 } 309 }
363 310
364 { 311 {
365 let guard = rwlock.read_lock().await; 312 let guard = rwlock.read().await;
366 assert_eq!(*guard, [0, 1]); 313 assert_eq!(*guard, [0, 1]);
367 } 314 }
368 315
369 assert_eq!(*rwlock.read_lock().await, [0, 1]); 316 assert_eq!(*rwlock.read().await, [0, 1]);
370 } 317 }
371 318
372 #[futures_test::test] 319 #[futures_test::test]
373 async fn write_guard_releases_lock_when_dropped() { 320 async fn write_guard_releases_lock_when_dropped() {
374 let rwlock: RwLock<NoopRawRwLock, [i32; 2]> = RwLock::new([0, 1]); 321 let rwlock: RwLock<NoopRawMutex, [i32; 2]> = RwLock::new([0, 1]);
375 322
376 { 323 {
377 let mut guard = rwlock.write_lock().await; 324 let mut guard = rwlock.write().await;
378 assert_eq!(*guard, [0, 1]); 325 assert_eq!(*guard, [0, 1]);
379 guard[1] = 2; 326 guard[1] = 2;
380 } 327 }
381 328
382 { 329 {
383 let guard = rwlock.read_lock().await; 330 let guard = rwlock.read().await;
384 assert_eq!(*guard, [0, 2]); 331 assert_eq!(*guard, [0, 2]);
385 } 332 }
386 333
387 assert_eq!(*rwlock.read_lock().await, [0, 2]); 334 assert_eq!(*rwlock.read().await, [0, 2]);
388 } 335 }
389} 336}