diff options
| author | Alix ANNERAUD <[email protected]> | 2025-02-28 23:26:59 +0100 |
|---|---|---|
| committer | Alix ANNERAUD <[email protected]> | 2025-02-28 23:26:59 +0100 |
| commit | 9cbdc9f11d8e0b857ed9bf483120da03ed3a878c (patch) | |
| tree | 975b2d7cfd7258d15063d40489ff608407df6ab7 | |
| parent | 55684782258b0241ede93ac6e43a07a3075ad028 (diff) | |
Implement read-write lock methods in CriticalSectionRawRwLock and update tests
| -rw-r--r-- | embassy-sync/src/blocking_rwlock/raw.rs | 57 | ||||
| -rw-r--r-- | embassy-sync/src/rwlock.rs | 2 |
2 files changed, 52 insertions, 7 deletions
diff --git a/embassy-sync/src/blocking_rwlock/raw.rs b/embassy-sync/src/blocking_rwlock/raw.rs index 7725edfa5..dc25e6305 100644 --- a/embassy-sync/src/blocking_rwlock/raw.rs +++ b/embassy-sync/src/blocking_rwlock/raw.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | //! Read-Write Lock primitives. | 1 | //! Read-Write Lock primitives. |
| 2 | //! | 2 | //! |
| 3 | //! This module provides a trait for read-write locks that can be used in different contexts. | 3 | //! This module provides a trait for read-write locks that can be used in different contexts. |
| 4 | use core::marker::PhantomData; | 4 | use core::{cell::RefCell, marker::PhantomData}; |
| 5 | 5 | ||
| 6 | /// Raw read-write lock trait. | 6 | /// Raw read-write lock trait. |
| 7 | /// | 7 | /// |
| @@ -41,15 +41,50 @@ pub unsafe trait RawRwLock { | |||
| 41 | /// | 41 | /// |
| 42 | /// This read-write lock is safe to share between different executors and interrupts. | 42 | /// This read-write lock is safe to share between different executors and interrupts. |
| 43 | pub struct CriticalSectionRawRwLock { | 43 | pub struct CriticalSectionRawRwLock { |
| 44 | _phantom: PhantomData<()>, | 44 | state: RefCell<isize>, |
| 45 | } | 45 | } |
| 46 | |||
| 46 | unsafe impl Send for CriticalSectionRawRwLock {} | 47 | unsafe impl Send for CriticalSectionRawRwLock {} |
| 47 | unsafe impl Sync for CriticalSectionRawRwLock {} | 48 | unsafe impl Sync for CriticalSectionRawRwLock {} |
| 48 | 49 | ||
| 49 | impl CriticalSectionRawRwLock { | 50 | impl CriticalSectionRawRwLock { |
| 50 | /// Create a new `CriticalSectionRawRwLock`. | 51 | /// Creates a new [`CriticalSectionRawRwLock`]. |
| 51 | pub const fn new() -> Self { | 52 | pub const fn new() -> Self { |
| 52 | Self { _phantom: PhantomData } | 53 | Self { state: RefCell::new(0) } |
| 54 | } | ||
| 55 | |||
| 56 | fn lock_read(&self) { | ||
| 57 | critical_section::with(|_| { | ||
| 58 | let mut state = self.state.borrow_mut(); | ||
| 59 | |||
| 60 | while *state & WRITER != 0 { | ||
| 61 | // Spin until the writer releases the lock | ||
| 62 | } | ||
| 63 | *state += 1; | ||
| 64 | }); | ||
| 65 | } | ||
| 66 | |||
| 67 | fn unlock_read(&self) { | ||
| 68 | critical_section::with(|_| { | ||
| 69 | *self.state.borrow_mut() -= 1; | ||
| 70 | }); | ||
| 71 | } | ||
| 72 | |||
| 73 | fn lock_write(&self) { | ||
| 74 | critical_section::with(|_| { | ||
| 75 | let mut state = self.state.borrow_mut(); | ||
| 76 | |||
| 77 | while *state != 0 { | ||
| 78 | // Spin until all readers and writers release the lock | ||
| 79 | } | ||
| 80 | *state = WRITER; | ||
| 81 | }); | ||
| 82 | } | ||
| 83 | |||
| 84 | fn unlock_write(&self) { | ||
| 85 | critical_section::with(|_| { | ||
| 86 | *self.state.borrow_mut() = 0; | ||
| 87 | }); | ||
| 53 | } | 88 | } |
| 54 | } | 89 | } |
| 55 | 90 | ||
| @@ -57,14 +92,24 @@ unsafe impl RawRwLock for CriticalSectionRawRwLock { | |||
| 57 | const INIT: Self = Self::new(); | 92 | const INIT: Self = Self::new(); |
| 58 | 93 | ||
| 59 | fn read_lock<R>(&self, f: impl FnOnce() -> R) -> R { | 94 | fn read_lock<R>(&self, f: impl FnOnce() -> R) -> R { |
| 60 | critical_section::with(|_| f()) | 95 | self.lock_read(); |
| 96 | let result = f(); | ||
| 97 | self.unlock_read(); | ||
| 98 | result | ||
| 61 | } | 99 | } |
| 62 | 100 | ||
| 63 | fn write_lock<R>(&self, f: impl FnOnce() -> R) -> R { | 101 | fn write_lock<R>(&self, f: impl FnOnce() -> R) -> R { |
| 64 | critical_section::with(|_| f()) | 102 | self.lock_write(); |
| 103 | let result = f(); | ||
| 104 | self.unlock_write(); | ||
| 105 | result | ||
| 65 | } | 106 | } |
| 66 | } | 107 | } |
| 67 | 108 | ||
| 109 | const WRITER: isize = -1; | ||
| 110 | |||
| 111 | // The rest of the file remains unchanged | ||
| 112 | |||
| 68 | // ================ | 113 | // ================ |
| 69 | 114 | ||
| 70 | /// A read-write lock that allows borrowing data in the context of a single executor. | 115 | /// A read-write lock that allows borrowing data in the context of a single executor. |
diff --git a/embassy-sync/src/rwlock.rs b/embassy-sync/src/rwlock.rs index 9fa61ee56..0ad5d5864 100644 --- a/embassy-sync/src/rwlock.rs +++ b/embassy-sync/src/rwlock.rs | |||
| @@ -350,7 +350,7 @@ where | |||
| 350 | #[cfg(test)] | 350 | #[cfg(test)] |
| 351 | mod tests { | 351 | mod tests { |
| 352 | use crate::blocking_rwlock::raw::NoopRawRwLock; | 352 | use crate::blocking_rwlock::raw::NoopRawRwLock; |
| 353 | use crate::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; | 353 | use crate::rwlock::RwLock; |
| 354 | 354 | ||
| 355 | #[futures_test::test] | 355 | #[futures_test::test] |
| 356 | async fn read_guard_releases_lock_when_dropped() { | 356 | async fn read_guard_releases_lock_when_dropped() { |
