diff options
| -rw-r--r-- | embassy-sync/src/blocking_rwlock/mod.rs | 6 | ||||
| -rw-r--r-- | embassy-sync/src/blocking_rwlock/raw.rs | 12 | ||||
| -rw-r--r-- | embassy-sync/src/rwlock.rs | 376 |
3 files changed, 265 insertions, 129 deletions
diff --git a/embassy-sync/src/blocking_rwlock/mod.rs b/embassy-sync/src/blocking_rwlock/mod.rs index a304b77d6..a8fb7d6bc 100644 --- a/embassy-sync/src/blocking_rwlock/mod.rs +++ b/embassy-sync/src/blocking_rwlock/mod.rs | |||
| @@ -1,11 +1,11 @@ | |||
| 1 | //! Blocking read-write lock. | 1 | //! Blocking read-write lock. |
| 2 | //! | 2 | //! |
| 3 | //! This module provides a blocking read-write lock that can be used to synchronize data. | 3 | //! This module provides a blocking read-write lock that can be used to synchronize data. |
| 4 | pub mod raw_rwlock; | 4 | pub mod raw; |
| 5 | 5 | ||
| 6 | use core::cell::UnsafeCell; | 6 | use core::cell::UnsafeCell; |
| 7 | 7 | ||
| 8 | use self::raw_rwlock::RawRwLock; | 8 | use self::raw::RawRwLock; |
| 9 | 9 | ||
| 10 | /// Blocking read-write lock (not async) | 10 | /// Blocking read-write lock (not async) |
| 11 | /// | 11 | /// |
| @@ -218,4 +218,4 @@ mod thread_mode_rwlock { | |||
| 218 | // Drop of the inner `T` happens after this. | 218 | // Drop of the inner `T` happens after this. |
| 219 | } | 219 | } |
| 220 | } | 220 | } |
| 221 | } \ No newline at end of file | 221 | } |
diff --git a/embassy-sync/src/blocking_rwlock/raw.rs b/embassy-sync/src/blocking_rwlock/raw.rs index 85e8374b5..7725edfa5 100644 --- a/embassy-sync/src/blocking_rwlock/raw.rs +++ b/embassy-sync/src/blocking_rwlock/raw.rs | |||
| @@ -126,13 +126,19 @@ mod thread_mode { | |||
| 126 | unsafe impl RawRwLock for ThreadModeRawRwLock { | 126 | unsafe impl RawRwLock for ThreadModeRawRwLock { |
| 127 | const INIT: Self = Self::new(); | 127 | const INIT: Self = Self::new(); |
| 128 | fn read_lock<R>(&self, f: impl FnOnce() -> R) -> R { | 128 | fn read_lock<R>(&self, f: impl FnOnce() -> R) -> R { |
| 129 | assert!(in_thread_mode(), "ThreadModeRwLock can only be locked from thread mode."); | 129 | assert!( |
| 130 | in_thread_mode(), | ||
| 131 | "ThreadModeRwLock can only be locked from thread mode." | ||
| 132 | ); | ||
| 130 | 133 | ||
| 131 | f() | 134 | f() |
| 132 | } | 135 | } |
| 133 | 136 | ||
| 134 | fn write_lock<R>(&self, f: impl FnOnce() -> R) -> R { | 137 | fn write_lock<R>(&self, f: impl FnOnce() -> R) -> R { |
| 135 | assert!(in_thread_mode(), "ThreadModeRwLock can only be locked from thread mode."); | 138 | assert!( |
| 139 | in_thread_mode(), | ||
| 140 | "ThreadModeRwLock can only be locked from thread mode." | ||
| 141 | ); | ||
| 136 | 142 | ||
| 137 | f() | 143 | f() |
| 138 | } | 144 | } |
| @@ -156,4 +162,4 @@ mod thread_mode { | |||
| 156 | } | 162 | } |
| 157 | } | 163 | } |
| 158 | #[cfg(any(cortex_m, feature = "std"))] | 164 | #[cfg(any(cortex_m, feature = "std"))] |
| 159 | pub use thread_mode::*; \ No newline at end of file | 165 | pub use thread_mode::*; |
diff --git a/embassy-sync/src/rwlock.rs b/embassy-sync/src/rwlock.rs index 30e1e74ad..365f6fda5 100644 --- a/embassy-sync/src/rwlock.rs +++ b/embassy-sync/src/rwlock.rs | |||
| @@ -1,134 +1,160 @@ | |||
| 1 | use core::cell::UnsafeCell; | 1 | //! Async read-write lock. |
| 2 | use core::future::poll_fn; | 2 | //! |
| 3 | //! This module provides a read-write lock that can be used to synchronize data between asynchronous tasks. | ||
| 4 | use core::cell::{RefCell, UnsafeCell}; | ||
| 5 | use core::future::{poll_fn, Future}; | ||
| 3 | use core::ops::{Deref, DerefMut}; | 6 | use core::ops::{Deref, DerefMut}; |
| 4 | use core::task::Poll; | 7 | use core::task::Poll; |
| 8 | use core::{fmt, mem}; | ||
| 5 | 9 | ||
| 6 | use crate::blocking_mutex::Mutex as BlockingMutex; | 10 | use crate::blocking_mutex::raw::RawRwLock; |
| 11 | use crate::blocking_mutex::RwLock as BlockingRwLock; | ||
| 7 | use crate::waitqueue::WakerRegistration; | 12 | use crate::waitqueue::WakerRegistration; |
| 8 | use crate::raw_rwlock::RawRwLock; | ||
| 9 | 13 | ||
| 10 | pub struct RwLock<M, T> | 14 | /// Error returned by [`RwLock::try_read_lock`] and [`RwLock::try_write_lock`] |
| 15 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] | ||
| 16 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 17 | pub struct TryLockError; | ||
| 18 | |||
| 19 | struct State { | ||
| 20 | readers: usize, | ||
| 21 | writer: bool, | ||
| 22 | waker: WakerRegistration, | ||
| 23 | } | ||
| 24 | |||
| 25 | /// Async read-write lock. | ||
| 26 | /// | ||
| 27 | /// The read-write lock is generic over a blocking [`RawRwLock`](crate::blocking_mutex::raw_rwlock::RawRwLock). | ||
| 28 | /// The raw read-write lock is used to guard access to the internal state. It | ||
| 29 | /// is held for very short periods only, while locking and unlocking. It is *not* held | ||
| 30 | /// for the entire time the async RwLock is locked. | ||
| 31 | /// | ||
| 32 | /// Which implementation you select depends on the context in which you're using the read-write lock. | ||
| 33 | /// | ||
| 34 | /// Use [`CriticalSectionRawRwLock`](crate::blocking_mutex::raw_rwlock::CriticalSectionRawRwLock) when data can be shared between threads and interrupts. | ||
| 35 | /// | ||
| 36 | /// Use [`NoopRawRwLock`](crate::blocking_mutex::raw_rwlock::NoopRawRwLock) when data is only shared between tasks running on the same executor. | ||
| 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. | ||
| 39 | /// | ||
| 40 | pub struct RwLock<R, T> | ||
| 11 | where | 41 | where |
| 12 | M: RawRwLock, | 42 | R: RawRwLock, |
| 13 | T: ?Sized, | 43 | T: ?Sized, |
| 14 | { | 44 | { |
| 15 | state: BlockingMutex<M, RwLockState>, | 45 | state: BlockingRwLock<R, RefCell<State>>, |
| 16 | inner: UnsafeCell<T>, | 46 | inner: UnsafeCell<T>, |
| 17 | } | 47 | } |
| 18 | 48 | ||
| 19 | unsafe impl<M: RawRwLock + Send, T: ?Sized + Send> Send for RwLock<M, T> {} | 49 | unsafe impl<R: RawRwLock + Send, T: ?Sized + Send> Send for RwLock<R, T> {} |
| 20 | unsafe impl<M: RawRwLock + Sync, T: ?Sized + Send> Sync for RwLock<M, T> {} | 50 | unsafe impl<R: RawRwLock + Sync, T: ?Sized + Send> Sync for RwLock<R, T> {} |
| 21 | 51 | ||
| 22 | impl<M, T> RwLock<M, T> | 52 | /// Async read-write lock. |
| 53 | impl<R, T> RwLock<R, T> | ||
| 23 | where | 54 | where |
| 24 | M: RawRwLock, | 55 | R: RawRwLock, |
| 25 | { | 56 | { |
| 57 | /// Create a new read-write lock with the given value. | ||
| 26 | pub const fn new(value: T) -> Self { | 58 | pub const fn new(value: T) -> Self { |
| 27 | Self { | 59 | Self { |
| 28 | inner: UnsafeCell::new(value), | 60 | inner: UnsafeCell::new(value), |
| 29 | state: BlockingMutex::new(RwLockState { | 61 | state: BlockingRwLock::new(RefCell::new(State { |
| 30 | locked: LockedState::Unlocked, | 62 | readers: 0, |
| 31 | writer_pending: 0, | 63 | writer: false, |
| 32 | readers_pending: 0, | ||
| 33 | waker: WakerRegistration::new(), | 64 | waker: WakerRegistration::new(), |
| 34 | }), | 65 | })), |
| 35 | } | 66 | } |
| 36 | } | 67 | } |
| 37 | } | 68 | } |
| 38 | 69 | ||
| 39 | impl<M, T> RwLock<M, T> | 70 | impl<R, T> RwLock<R, T> |
| 40 | where | 71 | where |
| 41 | M: RawRwLock, | 72 | R: RawRwLock, |
| 42 | T: ?Sized, | 73 | T: ?Sized, |
| 43 | { | 74 | { |
| 44 | pub fn read(&self) -> impl Future<Output = RwLockReadGuard<'_, M, T>> { | 75 | /// Lock the read-write lock for reading. |
| 76 | /// | ||
| 77 | /// 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>> { | ||
| 45 | poll_fn(|cx| { | 79 | poll_fn(|cx| { |
| 46 | let ready = self.state.lock(|s| { | 80 | let ready = self.state.lock(|s| { |
| 47 | let mut s = s.borrow_mut(); | 81 | let mut s = s.borrow_mut(); |
| 48 | match s.locked { | 82 | if s.writer { |
| 49 | LockedState::Unlocked => { | 83 | s.waker.register(cx.waker()); |
| 50 | s.locked = LockedState::ReadLocked(1); | 84 | false |
| 51 | true | 85 | } else { |
| 52 | } | 86 | s.readers += 1; |
| 53 | LockedState::ReadLocked(ref mut count) => { | 87 | true |
| 54 | *count += 1; | ||
| 55 | true | ||
| 56 | } | ||
| 57 | LockedState::WriteLocked => { | ||
| 58 | s.readers_pending += 1; | ||
| 59 | s.waker.register(cx.waker()); | ||
| 60 | false | ||
| 61 | } | ||
| 62 | } | 88 | } |
| 63 | }); | 89 | }); |
| 64 | 90 | ||
| 65 | if ready { | 91 | if ready { |
| 66 | Poll::Ready(RwLockReadGuard { lock: self }) | 92 | Poll::Ready(RwLockReadGuard { rwlock: self }) |
| 67 | } else { | 93 | } else { |
| 68 | Poll::Pending | 94 | Poll::Pending |
| 69 | } | 95 | } |
| 70 | }) | 96 | }) |
| 71 | } | 97 | } |
| 72 | 98 | ||
| 73 | pub fn write(&self) -> impl Future<Output = RwLockWriteGuard<'_, M, T>> { | 99 | /// Lock the read-write lock for writing. |
| 100 | /// | ||
| 101 | /// 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>> { | ||
| 74 | poll_fn(|cx| { | 103 | poll_fn(|cx| { |
| 75 | let ready = self.state.lock(|s| { | 104 | let ready = self.state.lock(|s| { |
| 76 | let mut s = s.borrow_mut(); | 105 | let mut s = s.borrow_mut(); |
| 77 | match s.locked { | 106 | if s.readers > 0 || s.writer { |
| 78 | LockedState::Unlocked => { | 107 | s.waker.register(cx.waker()); |
| 79 | s.locked = LockedState::WriteLocked; | 108 | false |
| 80 | true | 109 | } else { |
| 81 | } | 110 | s.writer = true; |
| 82 | _ => { | 111 | true |
| 83 | s.writer_pending += 1; | ||
| 84 | s.waker.register(cx.waker()); | ||
| 85 | false | ||
| 86 | } | ||
| 87 | } | 112 | } |
| 88 | }); | 113 | }); |
| 89 | 114 | ||
| 90 | if ready { | 115 | if ready { |
| 91 | Poll::Ready(RwLockWriteGuard { lock: self }) | 116 | Poll::Ready(RwLockWriteGuard { rwlock: self }) |
| 92 | } else { | 117 | } else { |
| 93 | Poll::Pending | 118 | Poll::Pending |
| 94 | } | 119 | } |
| 95 | }) | 120 | }) |
| 96 | } | 121 | } |
| 97 | 122 | ||
| 98 | pub fn try_read(&self) -> Result<RwLockReadGuard<'_, M, T>, TryLockError> { | 123 | /// Attempt to immediately lock the read-write lock for reading. |
| 124 | /// | ||
| 125 | /// If the lock is already locked for writing, this will return an error instead of waiting. | ||
| 126 | pub fn try_read_lock(&self) -> Result<RwLockReadGuard<'_, R, T>, TryLockError> { | ||
| 99 | self.state.lock(|s| { | 127 | self.state.lock(|s| { |
| 100 | let mut s = s.borrow_mut(); | 128 | let mut s = s.borrow_mut(); |
| 101 | match s.locked { | 129 | if s.writer { |
| 102 | LockedState::Unlocked => { | 130 | Err(TryLockError) |
| 103 | s.locked = LockedState::ReadLocked(1); | 131 | } else { |
| 104 | Ok(()) | 132 | s.readers += 1; |
| 105 | } | 133 | Ok(()) |
| 106 | LockedState::ReadLocked(ref mut count) => { | ||
| 107 | *count += 1; | ||
| 108 | Ok(()) | ||
| 109 | } | ||
| 110 | LockedState::WriteLocked => Err(TryLockError), | ||
| 111 | } | 134 | } |
| 112 | })?; | 135 | })?; |
| 113 | 136 | ||
| 114 | Ok(RwLockReadGuard { lock: self }) | 137 | Ok(RwLockReadGuard { rwlock: self }) |
| 115 | } | 138 | } |
| 116 | 139 | ||
| 117 | pub fn try_write(&self) -> Result<RwLockWriteGuard<'_, M, T>, TryLockError> { | 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> { | ||
| 118 | self.state.lock(|s| { | 144 | self.state.lock(|s| { |
| 119 | let mut s = s.borrow_mut(); | 145 | let mut s = s.borrow_mut(); |
| 120 | match s.locked { | 146 | if s.readers > 0 || s.writer { |
| 121 | LockedState::Unlocked => { | 147 | Err(TryLockError) |
| 122 | s.locked = LockedState::WriteLocked; | 148 | } else { |
| 123 | Ok(()) | 149 | s.writer = true; |
| 124 | } | 150 | Ok(()) |
| 125 | _ => Err(TryLockError), | ||
| 126 | } | 151 | } |
| 127 | })?; | 152 | })?; |
| 128 | 153 | ||
| 129 | Ok(RwLockWriteGuard { lock: self }) | 154 | Ok(RwLockWriteGuard { rwlock: self }) |
| 130 | } | 155 | } |
| 131 | 156 | ||
| 157 | /// Consumes this read-write lock, returning the underlying data. | ||
| 132 | pub fn into_inner(self) -> T | 158 | pub fn into_inner(self) -> T |
| 133 | where | 159 | where |
| 134 | T: Sized, | 160 | T: Sized, |
| @@ -136,20 +162,24 @@ where | |||
| 136 | self.inner.into_inner() | 162 | self.inner.into_inner() |
| 137 | } | 163 | } |
| 138 | 164 | ||
| 165 | /// Returns a mutable reference to the underlying data. | ||
| 166 | /// | ||
| 167 | /// Since this call borrows the RwLock mutably, no actual locking needs to | ||
| 168 | /// take place -- the mutable borrow statically guarantees no locks exist. | ||
| 139 | pub fn get_mut(&mut self) -> &mut T { | 169 | pub fn get_mut(&mut self) -> &mut T { |
| 140 | self.inner.get_mut() | 170 | self.inner.get_mut() |
| 141 | } | 171 | } |
| 142 | } | 172 | } |
| 143 | 173 | ||
| 144 | impl<M: RawRwLock, T> From<T> for RwLock<M, T> { | 174 | impl<R: RawRwLock, T> From<T> for RwLock<R, T> { |
| 145 | fn from(from: T) -> Self { | 175 | fn from(from: T) -> Self { |
| 146 | Self::new(from) | 176 | Self::new(from) |
| 147 | } | 177 | } |
| 148 | } | 178 | } |
| 149 | 179 | ||
| 150 | impl<M, T> Default for RwLock<M, T> | 180 | impl<R, T> Default for RwLock<R, T> |
| 151 | where | 181 | where |
| 152 | M: RawRwLock, | 182 | R: RawRwLock, |
| 153 | T: Default, | 183 | T: Default, |
| 154 | { | 184 | { |
| 155 | fn default() -> Self { | 185 | fn default() -> Self { |
| @@ -157,103 +187,203 @@ where | |||
| 157 | } | 187 | } |
| 158 | } | 188 | } |
| 159 | 189 | ||
| 160 | pub struct RwLockReadGuard<'a, M, T> | 190 | impl<R, T> fmt::Debug for RwLock<R, T> |
| 191 | where | ||
| 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. | ||
| 211 | /// | ||
| 212 | /// Owning an instance of this type indicates having | ||
| 213 | /// successfully locked the read-write lock for reading, and grants access to the contents. | ||
| 214 | /// | ||
| 215 | /// Dropping it unlocks the read-write lock. | ||
| 216 | #[clippy::has_significant_drop] | ||
| 217 | #[must_use = "if unused the RwLock will immediately unlock"] | ||
| 218 | pub struct RwLockReadGuard<'a, R, T> | ||
| 161 | where | 219 | where |
| 162 | M: RawRwLock, | 220 | R: RawRwLock, |
| 163 | T: ?Sized, | 221 | T: ?Sized, |
| 164 | { | 222 | { |
| 165 | lock: &'a RwLock<M, T>, | 223 | rwlock: &'a RwLock<R, T>, |
| 166 | } | 224 | } |
| 167 | 225 | ||
| 168 | impl<'a, M, T> Deref for RwLockReadGuard<'a, M, T> | 226 | impl<'a, R, T> Drop for RwLockReadGuard<'a, R, T> |
| 169 | where | 227 | where |
| 170 | M: RawRwLock, | 228 | R: RawRwLock, |
| 171 | T: ?Sized, | 229 | T: ?Sized, |
| 172 | { | 230 | { |
| 173 | type Target = T; | 231 | fn drop(&mut self) { |
| 232 | self.rwlock.state.lock(|s| { | ||
| 233 | let mut s = unwrap!(s.try_borrow_mut()); | ||
| 234 | s.readers -= 1; | ||
| 235 | if s.readers == 0 { | ||
| 236 | s.waker.wake(); | ||
| 237 | } | ||
| 238 | }) | ||
| 239 | } | ||
| 240 | } | ||
| 174 | 241 | ||
| 242 | impl<'a, R, T> Deref for RwLockReadGuard<'a, R, T> | ||
| 243 | where | ||
| 244 | R: RawRwLock, | ||
| 245 | T: ?Sized, | ||
| 246 | { | ||
| 247 | type Target = T; | ||
| 175 | fn deref(&self) -> &Self::Target { | 248 | fn deref(&self) -> &Self::Target { |
| 176 | unsafe { &*self.lock.inner.get() } | 249 | // Safety: the RwLockReadGuard represents shared access to the contents |
| 250 | // of the read-write lock, so it's OK to get it. | ||
| 251 | unsafe { &*(self.rwlock.inner.get() as *const T) } | ||
| 177 | } | 252 | } |
| 178 | } | 253 | } |
| 179 | 254 | ||
| 180 | impl<'a, M, T> Drop for RwLockReadGuard<'a, M, T> | 255 | impl<'a, R, T> fmt::Debug for RwLockReadGuard<'a, R, T> |
| 181 | where | 256 | where |
| 182 | M: RawRwLock, | 257 | R: RawRwLock, |
| 183 | T: ?Sized, | 258 | T: ?Sized + fmt::Debug, |
| 184 | { | 259 | { |
| 185 | fn drop(&mut self) { | 260 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 186 | self.lock.state.lock(|s| { | 261 | fmt::Debug::fmt(&**self, f) |
| 187 | let mut s = s.borrow_mut(); | ||
| 188 | match s.locked { | ||
| 189 | LockedState::ReadLocked(ref mut count) => { | ||
| 190 | *count -= 1; | ||
| 191 | if *count == 0 { | ||
| 192 | s.locked = LockedState::Unlocked; | ||
| 193 | s.waker.wake(); | ||
| 194 | } | ||
| 195 | } | ||
| 196 | _ => unreachable!(), | ||
| 197 | } | ||
| 198 | }); | ||
| 199 | } | 262 | } |
| 200 | } | 263 | } |
| 201 | 264 | ||
| 202 | pub struct RwLockWriteGuard<'a, M, T> | 265 | impl<'a, R, T> fmt::Display for RwLockReadGuard<'a, R, T> |
| 203 | where | 266 | where |
| 204 | M: RawRwLock, | 267 | R: RawRwLock, |
| 268 | T: ?Sized + fmt::Display, | ||
| 269 | { | ||
| 270 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
| 271 | fmt::Display::fmt(&**self, f) | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | /// Async write lock guard. | ||
| 276 | /// | ||
| 277 | /// Owning an instance of this type indicates having | ||
| 278 | /// successfully locked the read-write lock for writing, and grants access to the contents. | ||
| 279 | /// | ||
| 280 | /// Dropping it unlocks the read-write lock. | ||
| 281 | #[clippy::has_significant_drop] | ||
| 282 | #[must_use = "if unused the RwLock will immediately unlock"] | ||
| 283 | pub struct RwLockWriteGuard<'a, R, T> | ||
| 284 | where | ||
| 285 | R: RawRwLock, | ||
| 205 | T: ?Sized, | 286 | T: ?Sized, |
| 206 | { | 287 | { |
| 207 | lock: &'a RwLock<M, T>, | 288 | rwlock: &'a RwLock<R, T>, |
| 208 | } | 289 | } |
| 209 | 290 | ||
| 210 | impl<'a, M, T> Deref for RwLockWriteGuard<'a, M, T> | 291 | impl<'a, R, T> Drop for RwLockWriteGuard<'a, R, T> |
| 211 | where | 292 | where |
| 212 | M: RawRwLock, | 293 | R: RawRwLock, |
| 213 | T: ?Sized, | 294 | T: ?Sized, |
| 214 | { | 295 | { |
| 215 | type Target = T; | 296 | fn drop(&mut self) { |
| 297 | self.rwlock.state.lock(|s| { | ||
| 298 | let mut s = unwrap!(s.try_borrow_mut()); | ||
| 299 | s.writer = false; | ||
| 300 | s.waker.wake(); | ||
| 301 | }) | ||
| 302 | } | ||
| 303 | } | ||
| 216 | 304 | ||
| 305 | impl<'a, R, T> Deref for RwLockWriteGuard<'a, R, T> | ||
| 306 | where | ||
| 307 | R: RawRwLock, | ||
| 308 | T: ?Sized, | ||
| 309 | { | ||
| 310 | type Target = T; | ||
| 217 | fn deref(&self) -> &Self::Target { | 311 | fn deref(&self) -> &Self::Target { |
| 218 | unsafe { &*self.lock.inner.get() } | 312 | // Safety: the RwLockWriteGuard represents exclusive access to the contents |
| 313 | // of the read-write lock, so it's OK to get it. | ||
| 314 | unsafe { &*(self.rwlock.inner.get() as *mut T) } | ||
| 219 | } | 315 | } |
| 220 | } | 316 | } |
| 221 | 317 | ||
| 222 | impl<'a, M, T> DerefMut for RwLockWriteGuard<'a, M, T> | 318 | impl<'a, R, T> DerefMut for RwLockWriteGuard<'a, R, T> |
| 223 | where | 319 | where |
| 224 | M: RawRwLock, | 320 | R: RawRwLock, |
| 225 | T: ?Sized, | 321 | T: ?Sized, |
| 226 | { | 322 | { |
| 227 | fn deref_mut(&mut self) -> &mut Self::Target { | 323 | fn deref_mut(&mut self) -> &mut Self::Target { |
| 228 | unsafe { &mut *self.lock.inner.get() } | 324 | // Safety: the RwLockWriteGuard represents exclusive access to the contents |
| 325 | // of the read-write lock, so it's OK to get it. | ||
| 326 | unsafe { &mut *(self.rwlock.inner.get()) } | ||
| 229 | } | 327 | } |
| 230 | } | 328 | } |
| 231 | 329 | ||
| 232 | impl<'a, M, T> Drop for RwLockWriteGuard<'a, M, T> | 330 | impl<'a, R, T> fmt::Debug for RwLockWriteGuard<'a, R, T> |
| 233 | where | 331 | where |
| 234 | M: RawRwLock, | 332 | R: RawRwLock, |
| 235 | T: ?Sized, | 333 | T: ?Sized + fmt::Debug, |
| 236 | { | 334 | { |
| 237 | fn drop(&mut self) { | 335 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 238 | self.lock.state.lock(|s| { | 336 | fmt::Debug::fmt(&**self, f) |
| 239 | let mut s = s.borrow_mut(); | ||
| 240 | s.locked = LockedState::Unlocked; | ||
| 241 | s.waker.wake(); | ||
| 242 | }); | ||
| 243 | } | 337 | } |
| 244 | } | 338 | } |
| 245 | 339 | ||
| 246 | struct RwLockState { | 340 | impl<'a, R, T> fmt::Display for RwLockWriteGuard<'a, R, T> |
| 247 | locked: LockedState, | 341 | where |
| 248 | writer_pending: usize, | 342 | R: RawRwLock, |
| 249 | readers_pending: usize, | 343 | T: ?Sized + fmt::Display, |
| 250 | waker: WakerRegistration, | 344 | { |
| 345 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
| 346 | fmt::Display::fmt(&**self, f) | ||
| 347 | } | ||
| 251 | } | 348 | } |
| 252 | 349 | ||
| 253 | enum LockedState { | 350 | #[cfg(test)] |
| 254 | Unlocked, | 351 | mod tests { |
| 255 | ReadLocked(usize), | 352 | use crate::blocking_mutex::raw_rwlock::NoopRawRwLock; |
| 256 | WriteLocked, | 353 | use crate::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; |
| 257 | } | ||
| 258 | 354 | ||
| 259 | pub struct TryLockError; | 355 | #[futures_test::test] |
| 356 | async fn read_guard_releases_lock_when_dropped() { | ||
| 357 | let rwlock: RwLock<NoopRawRwLock, [i32; 2]> = RwLock::new([0, 1]); | ||
| 358 | |||
| 359 | { | ||
| 360 | let guard = rwlock.read_lock().await; | ||
| 361 | assert_eq!(*guard, [0, 1]); | ||
| 362 | } | ||
| 363 | |||
| 364 | { | ||
| 365 | let guard = rwlock.read_lock().await; | ||
| 366 | assert_eq!(*guard, [0, 1]); | ||
| 367 | } | ||
| 368 | |||
| 369 | assert_eq!(*rwlock.read_lock().await, [0, 1]); | ||
| 370 | } | ||
| 371 | |||
| 372 | #[futures_test::test] | ||
| 373 | async fn write_guard_releases_lock_when_dropped() { | ||
| 374 | let rwlock: RwLock<NoopRawRwLock, [i32; 2]> = RwLock::new([0, 1]); | ||
| 375 | |||
| 376 | { | ||
| 377 | let mut guard = rwlock.write_lock().await; | ||
| 378 | assert_eq!(*guard, [0, 1]); | ||
| 379 | guard[1] = 2; | ||
| 380 | } | ||
| 381 | |||
| 382 | { | ||
| 383 | let guard = rwlock.read_lock().await; | ||
| 384 | assert_eq!(*guard, [0, 2]); | ||
| 385 | } | ||
| 386 | |||
| 387 | assert_eq!(*rwlock.read_lock().await, [0, 2]); | ||
| 388 | } | ||
| 389 | } | ||
