Skip to content

Commit f9192f1

Browse files
committed
Implement RwaMutex for LocalRawMutex
1 parent ff128fb commit f9192f1

File tree

2 files changed

+89
-35
lines changed

2 files changed

+89
-35
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

source/mutex/src/raw_impls.rs

Lines changed: 87 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272

7373
use core::marker::PhantomData;
7474
use core::sync::atomic::{AtomicBool, Ordering};
75-
use mutex_traits::{ConstInit, ScopedRawMutex};
75+
use mutex_traits::{ConstInit, RawMutex, ScopedRawMutex};
7676

7777
pub use mutex_traits as traits;
7878

@@ -170,32 +170,72 @@ pub mod local {
170170
const INIT: Self = Self::new();
171171
}
172172

173-
unsafe impl ScopedRawMutex for LocalRawMutex {
173+
unsafe impl RawMutex for LocalRawMutex {
174+
type GuardMarker = *mut ();
175+
174176
#[inline]
175-
fn try_with_lock<R>(&self, f: impl FnOnce() -> R) -> Option<R> {
176-
// NOTE: separated load/stores are acceptable as we are !Sync,
177-
// meaning that we can only be accessed within a single thread
178-
if self.taken.load(Ordering::Relaxed) {
179-
return None;
177+
fn lock(&self) {
178+
if !self.try_lock() {
179+
// In a local-only mutex, it is not possible for another holder
180+
// of this mutex to release, which means we have certainly
181+
// reached deadlock if the lock was already locked.
182+
panic!("Deadlocked");
180183
}
181-
self.taken.store(true, Ordering::Relaxed);
182-
let ret = f();
183-
self.taken.store(false, Ordering::Relaxed);
184-
Some(ret)
185184
}
186185

187186
#[inline]
188-
fn with_lock<R>(&self, f: impl FnOnce() -> R) -> R {
189-
// In a local-only mutex, it is not possible for another holder
190-
// of this mutex to release, which means we have certainly
191-
// reached deadlock if the lock was already locked.
192-
self.try_with_lock(f).expect("Deadlocked")
187+
fn try_lock(&self) -> bool {
188+
#[cfg(armv6m)]
189+
{
190+
// NOTE: separated load/stores are acceptable as we are !Sync,
191+
// meaning that we can only be accessed within a single thread
192+
if self.taken.load(Ordering::Relaxed) {
193+
return false;
194+
}
195+
self.taken.store(true, Ordering::Relaxed);
196+
return true;
197+
}
198+
#[cfg(not(armv6m))]
199+
self.taken
200+
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Relaxed)
201+
.is_ok()
193202
}
194203

204+
#[inline]
205+
unsafe fn unlock(&self) {
206+
self.taken.store(false, Ordering::Release);
207+
}
208+
209+
#[inline]
195210
fn is_locked(&self) -> bool {
196211
self.taken.load(Ordering::Relaxed)
197212
}
198213
}
214+
215+
#[cfg(feature = "std")]
216+
#[cfg(test)]
217+
mod test {
218+
use super::*;
219+
use crate::BlockingMutex;
220+
221+
#[test]
222+
fn local_raw_mutex() {
223+
let mutex = BlockingMutex::<LocalRawMutex, u32>::new(0);
224+
let mut guard = mutex.lock();
225+
assert_eq!(*guard, 0);
226+
*guard = 1;
227+
drop(guard);
228+
229+
let mut guard = mutex.lock();
230+
assert_eq!(*guard, 1);
231+
*guard = 2;
232+
drop(guard);
233+
234+
mutex.with_lock(|data| {
235+
assert_eq!(*data, 2);
236+
});
237+
}
238+
}
199239
}
200240

201241
// ================
@@ -210,7 +250,7 @@ pub mod single_core_thread_mode {
210250
///
211251
/// # Safety
212252
///
213-
/// **This Mutex is only safe on single-core systems.**
253+
/// **This Mutex is only safe on single-core bare-metal systems.**
214254
///
215255
/// On multi-core systems, a `ThreadModeRawMutex` **is not sufficient** to ensure exclusive access.
216256
#[cfg_attr(feature = "fmt", derive(Debug))]
@@ -234,30 +274,44 @@ pub mod single_core_thread_mode {
234274
const INIT: Self = Self::new();
235275
}
236276

237-
unsafe impl ScopedRawMutex for ThreadModeRawMutex {
277+
unsafe impl RawMutex for ThreadModeRawMutex {
278+
type GuardMarker = *mut ();
279+
238280
#[inline]
239-
fn try_with_lock<R>(&self, f: impl FnOnce() -> R) -> Option<R> {
281+
fn lock(&self) {
282+
if !self.try_lock() {
283+
// In a thread-mode only mutex, it is not possible for another holder
284+
// of this mutex to release, which means we have certainly
285+
// reached deadlock if the lock was already locked.
286+
panic!("Deadlocked or attempted to access outside of thread mode")
287+
}
288+
}
289+
290+
#[inline]
291+
fn try_lock(&self) -> bool {
240292
if !in_thread_mode() {
241-
return None;
293+
return false;
294+
}
295+
#[cfg(armv6m)]
296+
{
297+
// NOTE: separated load/stores are acceptable as we checked we are only
298+
// accessed from a single thread (checked above)
299+
assert!(!self.taken.load(Ordering::Relaxed));
300+
self.taken.store(true, Ordering::Relaxed);
301+
return true;
242302
}
243-
// NOTE: separated load/stores are acceptable as we checked we are only
244-
// accessed from a single thread (checked above)
245-
assert!(!self.taken.load(Ordering::Relaxed));
246-
self.taken.store(true, Ordering::Relaxed);
247-
let ret = f();
248-
self.taken.store(false, Ordering::Relaxed);
249-
Some(ret)
303+
#[cfg(not(armv6m))]
304+
self.taken
305+
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Relaxed)
306+
.is_ok()
250307
}
251308

252309
#[inline]
253-
fn with_lock<R>(&self, f: impl FnOnce() -> R) -> R {
254-
// In a thread-mode only mutex, it is not possible for another holder
255-
// of this mutex to release, which means we have certainly
256-
// reached deadlock if the lock was already locked.
257-
self.try_with_lock(f)
258-
.expect("Deadlocked or attempted to access outside of thread mode")
310+
unsafe fn unlock(&self) {
311+
self.taken.store(false, Ordering::Release);
259312
}
260313

314+
#[inline]
261315
fn is_locked(&self) -> bool {
262316
self.taken.load(Ordering::Relaxed)
263317
}

0 commit comments

Comments
 (0)