1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};
use cortex_m::interrupt::{disable, enable};
use cortex_m::register::primask;
use cortex_m::register::primask::Primask;
pub struct Mutex<T> {
inner: UnsafeCell<T>,
}
// SAFETY: it is safe to share a Mutex between interrupts and
// other code. That's because there is only one thread, and the
// only way to access what is in a Mutex is by locking it, disabling
// interrupts. That means there are two cases:
// 1. We are in normal code, there can be no interrupt (since we turned those off)
// and since there's only one core, we know for sure we're alone in accessing the
// wrapped value
//
// 2. We are in an interrupt. In an interrupt, no other interrupts can occur. It
// is also impossible to have already locked the Mutex at this point, since to lock
// it outside an interrupt, interrupts had to be turned off. That means when we are
// in an interrupt, nothing else can have the Mutex locked, otherwise we could not
// actually be in an interrupt.
unsafe impl<T> Sync for Mutex<T> {}
impl<T> Mutex<T> {
pub const fn new(v: T) -> Self {
Self {
inner: UnsafeCell::new(v),
}
}
pub fn lock(&self) -> LockGuard<T> {
let primask = primask::read();
// disable interrupts
disable();
LockGuard {
// SAFETY: we disabled interrupts, creating a critical section.
// that means we can safely mutably access the internals of our
// UnsafeCell. Note that this is safe until interrupts are turned
// back on, which happens when users drop the LockGuard. Since the
// guard is the only way to access &mut T, this means that interrupts
// are turned on at the moment you can never have access to &mut T anymore
inner: unsafe { &mut *self.inner.get() },
primask,
}
}
/// This function gets a reference to the inner `T` _without_ locking the lock.
/// This is inherently unsafe.
///
/// # Safety
/// This function is only safe if you can guarantee that nothing is
/// mutating this or holding a lock while this reference exists. That means, you should
/// generally drop this reference ASAP.
///
/// This generally can be used in the following cases:
/// * You only access this from within interrupts, as interrupts themselves can not be interrupted
/// * You only access this outside of interrupts, as interrupts don't break the mutex guarantees
#[allow(clippy::mut_from_ref)]
pub unsafe fn no_critical_section_lock(&self) -> &mut T {
&mut *self.inner.get()
}
}
pub struct LockGuard<'a, T> {
inner: &'a mut T,
primask: Primask,
}
impl<T> Drop for LockGuard<'_, T> {
fn drop(&mut self) {
// If the interrupts were active before our `disable` call, then re-enable
// them. Otherwise, keep them disabled
if self.primask.is_active() {
unsafe { enable() }
}
}
}
impl<T> Deref for LockGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.inner
}
}
impl<T> DerefMut for LockGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.inner
}
}