Skip to content

Commit 84fef5e

Browse files
committed
Implement RwaMutex for LocalRawMutex
1 parent ff128fb commit 84fef5e

File tree

2 files changed

+69
-35
lines changed

2 files changed

+69
-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: 67 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,61 @@ 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+
self.taken
189+
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Relaxed)
190+
.is_ok()
193191
}
194192

193+
#[inline]
194+
unsafe fn unlock(&self) {
195+
self.taken.store(false, Ordering::Release);
196+
}
197+
198+
#[inline]
195199
fn is_locked(&self) -> bool {
196200
self.taken.load(Ordering::Relaxed)
197201
}
198202
}
203+
204+
#[cfg(feature = "std")]
205+
#[cfg(test)]
206+
mod test {
207+
use super::*;
208+
use crate::BlockingMutex;
209+
210+
#[test]
211+
fn local_raw_mutex() {
212+
let mutex = BlockingMutex::<LocalRawMutex, u32>::new(0);
213+
let mut guard = mutex.lock();
214+
assert_eq!(*guard, 0);
215+
*guard = 1;
216+
drop(guard);
217+
218+
let mut guard = mutex.lock();
219+
assert_eq!(*guard, 1);
220+
*guard = 2;
221+
drop(guard);
222+
223+
mutex.with_lock(|data| {
224+
assert_eq!(*data, 2);
225+
});
226+
}
227+
}
199228
}
200229

201230
// ================
@@ -210,7 +239,7 @@ pub mod single_core_thread_mode {
210239
///
211240
/// # Safety
212241
///
213-
/// **This Mutex is only safe on single-core systems.**
242+
/// **This Mutex is only safe on single-core bare-metal systems.**
214243
///
215244
/// On multi-core systems, a `ThreadModeRawMutex` **is not sufficient** to ensure exclusive access.
216245
#[cfg_attr(feature = "fmt", derive(Debug))]
@@ -234,30 +263,35 @@ pub mod single_core_thread_mode {
234263
const INIT: Self = Self::new();
235264
}
236265

237-
unsafe impl ScopedRawMutex for ThreadModeRawMutex {
266+
unsafe impl RawMutex for ThreadModeRawMutex {
267+
type GuardMarker = *mut ();
268+
238269
#[inline]
239-
fn try_with_lock<R>(&self, f: impl FnOnce() -> R) -> Option<R> {
270+
fn lock(&self) {
271+
if !self.try_lock() {
272+
// In a thread-mode only mutex, it is not possible for another holder
273+
// of this mutex to release, which means we have certainly
274+
// reached deadlock if the lock was already locked.
275+
panic!("Deadlocked or attempted to access outside of thread mode")
276+
}
277+
}
278+
279+
#[inline]
280+
fn try_lock(&self) -> bool {
240281
if !in_thread_mode() {
241-
return None;
282+
return false;
242283
}
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)
284+
self.taken
285+
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Relaxed)
286+
.is_ok()
250287
}
251288

252289
#[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")
290+
unsafe fn unlock(&self) {
291+
self.taken.store(false, Ordering::Release);
259292
}
260293

294+
#[inline]
261295
fn is_locked(&self) -> bool {
262296
self.taken.load(Ordering::Relaxed)
263297
}

0 commit comments

Comments
 (0)