diff options
| author | Jack Hogan <[email protected]> | 2024-04-15 14:15:53 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-04-15 14:15:53 -0400 |
| commit | aeb4daa22fb767b239781a3f9abd85e70c767917 (patch) | |
| tree | 4fa9ab1b443e08ad26bc01ef0fd0b11eb492f016 /embassy-sync | |
| parent | 6ffecb1250bbbdf7f1336479d8f7b7aa1fd00285 (diff) | |
| parent | 3f4e326ec5ec081742e9f30cb7b0bc936e74009c (diff) | |
Merge branch 'embassy-rs:main' into main
Diffstat (limited to 'embassy-sync')
| -rw-r--r-- | embassy-sync/CHANGELOG.md | 5 | ||||
| -rw-r--r-- | embassy-sync/src/channel.rs | 27 | ||||
| -rw-r--r-- | embassy-sync/src/mutex.rs | 133 |
3 files changed, 164 insertions, 1 deletions
diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md index e7db97ef7..3f6b39d8b 100644 --- a/embassy-sync/CHANGELOG.md +++ b/embassy-sync/CHANGELOG.md | |||
| @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. | |||
| 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), |
| 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). |
| 7 | 7 | ||
| 8 | ## Unreleased | ||
| 9 | |||
| 10 | - Add `len`, `is_empty` and `is_full` functions to `Channel`. | ||
| 11 | |||
| 8 | ## 0.5.0 - 2023-12-04 | 12 | ## 0.5.0 - 2023-12-04 |
| 9 | 13 | ||
| 10 | - Add a PriorityChannel. | 14 | - Add a PriorityChannel. |
| @@ -35,7 +39,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 35 | - Remove unnecessary uses of `atomic-polyfill` | 39 | - Remove unnecessary uses of `atomic-polyfill` |
| 36 | - Add `#[must_use]` to all futures. | 40 | - Add `#[must_use]` to all futures. |
| 37 | 41 | ||
| 38 | |||
| 39 | ## 0.1.0 - 2022-08-26 | 42 | ## 0.1.0 - 2022-08-26 |
| 40 | 43 | ||
| 41 | - First release | 44 | - First release |
diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs index 48f4dafd6..18be462cb 100644 --- a/embassy-sync/src/channel.rs +++ b/embassy-sync/src/channel.rs | |||
| @@ -449,6 +449,18 @@ impl<T, const N: usize> ChannelState<T, N> { | |||
| 449 | Poll::Pending | 449 | Poll::Pending |
| 450 | } | 450 | } |
| 451 | } | 451 | } |
| 452 | |||
| 453 | fn len(&self) -> usize { | ||
| 454 | self.queue.len() | ||
| 455 | } | ||
| 456 | |||
| 457 | fn is_empty(&self) -> bool { | ||
| 458 | self.queue.is_empty() | ||
| 459 | } | ||
| 460 | |||
| 461 | fn is_full(&self) -> bool { | ||
| 462 | self.queue.is_full() | ||
| 463 | } | ||
| 452 | } | 464 | } |
| 453 | 465 | ||
| 454 | /// A bounded channel for communicating between asynchronous tasks | 466 | /// A bounded channel for communicating between asynchronous tasks |
| @@ -572,6 +584,21 @@ where | |||
| 572 | pub fn try_receive(&self) -> Result<T, TryReceiveError> { | 584 | pub fn try_receive(&self) -> Result<T, TryReceiveError> { |
| 573 | self.lock(|c| c.try_receive()) | 585 | self.lock(|c| c.try_receive()) |
| 574 | } | 586 | } |
| 587 | |||
| 588 | /// Returns the number of elements currently in the channel. | ||
| 589 | pub fn len(&self) -> usize { | ||
| 590 | self.lock(|c| c.len()) | ||
| 591 | } | ||
| 592 | |||
| 593 | /// Returns whether the channel is empty. | ||
| 594 | pub fn is_empty(&self) -> bool { | ||
| 595 | self.lock(|c| c.is_empty()) | ||
| 596 | } | ||
| 597 | |||
| 598 | /// Returns whether the channel is full. | ||
| 599 | pub fn is_full(&self) -> bool { | ||
| 600 | self.lock(|c| c.is_full()) | ||
| 601 | } | ||
| 575 | } | 602 | } |
| 576 | 603 | ||
| 577 | /// Implements the DynamicChannel to allow creating types that are unaware of the queue size with the | 604 | /// Implements the DynamicChannel to allow creating types that are unaware of the queue size with the |
diff --git a/embassy-sync/src/mutex.rs b/embassy-sync/src/mutex.rs index 72459d660..b48a408c4 100644 --- a/embassy-sync/src/mutex.rs +++ b/embassy-sync/src/mutex.rs | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | //! This module provides a mutex that can be used to synchronize data between asynchronous tasks. | 3 | //! This module provides a mutex that can be used to synchronize data between asynchronous tasks. |
| 4 | use core::cell::{RefCell, UnsafeCell}; | 4 | use core::cell::{RefCell, UnsafeCell}; |
| 5 | use core::future::poll_fn; | 5 | use core::future::poll_fn; |
| 6 | use core::mem; | ||
| 6 | use core::ops::{Deref, DerefMut}; | 7 | use core::ops::{Deref, DerefMut}; |
| 7 | use core::task::Poll; | 8 | use core::task::Poll; |
| 8 | 9 | ||
| @@ -134,6 +135,7 @@ where | |||
| 134 | /// successfully locked the mutex, and grants access to the contents. | 135 | /// successfully locked the mutex, and grants access to the contents. |
| 135 | /// | 136 | /// |
| 136 | /// Dropping it unlocks the mutex. | 137 | /// Dropping it unlocks the mutex. |
| 138 | #[clippy::has_significant_drop] | ||
| 137 | pub struct MutexGuard<'a, M, T> | 139 | pub struct MutexGuard<'a, M, T> |
| 138 | where | 140 | where |
| 139 | M: RawMutex, | 141 | M: RawMutex, |
| @@ -142,6 +144,25 @@ where | |||
| 142 | mutex: &'a Mutex<M, T>, | 144 | mutex: &'a Mutex<M, T>, |
| 143 | } | 145 | } |
| 144 | 146 | ||
| 147 | impl<'a, M, T> MutexGuard<'a, M, T> | ||
| 148 | where | ||
| 149 | M: RawMutex, | ||
| 150 | T: ?Sized, | ||
| 151 | { | ||
| 152 | /// Returns a locked view over a portion of the locked data. | ||
| 153 | pub fn map<U>(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> { | ||
| 154 | let mutex = this.mutex; | ||
| 155 | let value = fun(unsafe { &mut *this.mutex.inner.get() }); | ||
| 156 | // Don't run the `drop` method for MutexGuard. The ownership of the underlying | ||
| 157 | // locked state is being moved to the returned MappedMutexGuard. | ||
| 158 | mem::forget(this); | ||
| 159 | MappedMutexGuard { | ||
| 160 | state: &mutex.state, | ||
| 161 | value, | ||
| 162 | } | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 145 | impl<'a, M, T> Drop for MutexGuard<'a, M, T> | 166 | impl<'a, M, T> Drop for MutexGuard<'a, M, T> |
| 146 | where | 167 | where |
| 147 | M: RawMutex, | 168 | M: RawMutex, |
| @@ -180,3 +201,115 @@ where | |||
| 180 | unsafe { &mut *(self.mutex.inner.get()) } | 201 | unsafe { &mut *(self.mutex.inner.get()) } |
| 181 | } | 202 | } |
| 182 | } | 203 | } |
| 204 | |||
| 205 | /// A handle to a held `Mutex` that has had a function applied to it via [`MutexGuard::map`] or | ||
| 206 | /// [`MappedMutexGuard::map`]. | ||
| 207 | /// | ||
| 208 | /// This can be used to hold a subfield of the protected data. | ||
| 209 | #[clippy::has_significant_drop] | ||
| 210 | pub struct MappedMutexGuard<'a, M, T> | ||
| 211 | where | ||
| 212 | M: RawMutex, | ||
| 213 | T: ?Sized, | ||
| 214 | { | ||
| 215 | state: &'a BlockingMutex<M, RefCell<State>>, | ||
| 216 | value: *mut T, | ||
| 217 | } | ||
| 218 | |||
| 219 | impl<'a, M, T> MappedMutexGuard<'a, M, T> | ||
| 220 | where | ||
| 221 | M: RawMutex, | ||
| 222 | T: ?Sized, | ||
| 223 | { | ||
| 224 | /// Returns a locked view over a portion of the locked data. | ||
| 225 | pub fn map<U>(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> { | ||
| 226 | let state = this.state; | ||
| 227 | let value = fun(unsafe { &mut *this.value }); | ||
| 228 | // Don't run the `drop` method for MutexGuard. The ownership of the underlying | ||
| 229 | // locked state is being moved to the returned MappedMutexGuard. | ||
| 230 | mem::forget(this); | ||
| 231 | MappedMutexGuard { state, value } | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | impl<'a, M, T> Deref for MappedMutexGuard<'a, M, T> | ||
| 236 | where | ||
| 237 | M: RawMutex, | ||
| 238 | T: ?Sized, | ||
| 239 | { | ||
| 240 | type Target = T; | ||
| 241 | fn deref(&self) -> &Self::Target { | ||
| 242 | // Safety: the MutexGuard represents exclusive access to the contents | ||
| 243 | // of the mutex, so it's OK to get it. | ||
| 244 | unsafe { &*self.value } | ||
| 245 | } | ||
| 246 | } | ||
| 247 | |||
| 248 | impl<'a, M, T> DerefMut for MappedMutexGuard<'a, M, T> | ||
| 249 | where | ||
| 250 | M: RawMutex, | ||
| 251 | T: ?Sized, | ||
| 252 | { | ||
| 253 | fn deref_mut(&mut self) -> &mut Self::Target { | ||
| 254 | // Safety: the MutexGuard represents exclusive access to the contents | ||
| 255 | // of the mutex, so it's OK to get it. | ||
| 256 | unsafe { &mut *self.value } | ||
| 257 | } | ||
| 258 | } | ||
| 259 | |||
| 260 | impl<'a, M, T> Drop for MappedMutexGuard<'a, M, T> | ||
| 261 | where | ||
| 262 | M: RawMutex, | ||
| 263 | T: ?Sized, | ||
| 264 | { | ||
| 265 | fn drop(&mut self) { | ||
| 266 | self.state.lock(|s| { | ||
| 267 | let mut s = unwrap!(s.try_borrow_mut()); | ||
| 268 | s.locked = false; | ||
| 269 | s.waker.wake(); | ||
| 270 | }) | ||
| 271 | } | ||
| 272 | } | ||
| 273 | |||
| 274 | unsafe impl<M, T> Send for MappedMutexGuard<'_, M, T> | ||
| 275 | where | ||
| 276 | M: RawMutex + Sync, | ||
| 277 | T: Send + ?Sized, | ||
| 278 | { | ||
| 279 | } | ||
| 280 | |||
| 281 | unsafe impl<M, T> Sync for MappedMutexGuard<'_, M, T> | ||
| 282 | where | ||
| 283 | M: RawMutex + Sync, | ||
| 284 | T: Sync + ?Sized, | ||
| 285 | { | ||
| 286 | } | ||
| 287 | |||
| 288 | #[cfg(test)] | ||
| 289 | mod tests { | ||
| 290 | use crate::blocking_mutex::raw::NoopRawMutex; | ||
| 291 | use crate::mutex::{Mutex, MutexGuard}; | ||
| 292 | |||
| 293 | #[futures_test::test] | ||
| 294 | async fn mapped_guard_releases_lock_when_dropped() { | ||
| 295 | let mutex: Mutex<NoopRawMutex, [i32; 2]> = Mutex::new([0, 1]); | ||
| 296 | |||
| 297 | { | ||
| 298 | let guard = mutex.lock().await; | ||
| 299 | assert_eq!(*guard, [0, 1]); | ||
| 300 | let mut mapped = MutexGuard::map(guard, |this| &mut this[1]); | ||
| 301 | assert_eq!(*mapped, 1); | ||
| 302 | *mapped = 2; | ||
| 303 | } | ||
| 304 | |||
| 305 | { | ||
| 306 | let guard = mutex.lock().await; | ||
| 307 | assert_eq!(*guard, [0, 2]); | ||
| 308 | let mut mapped = MutexGuard::map(guard, |this| &mut this[1]); | ||
| 309 | assert_eq!(*mapped, 2); | ||
| 310 | *mapped = 3; | ||
| 311 | } | ||
| 312 | |||
| 313 | assert_eq!(*mutex.lock().await, [0, 3]); | ||
| 314 | } | ||
| 315 | } | ||
