embassy-rp: Implementation of a SpinlockMutex
This commit is contained in:
parent
d17d43735f
commit
05a6f7a795
@ -42,6 +42,7 @@ pub mod rom_data;
|
||||
pub mod rtc;
|
||||
pub mod spi;
|
||||
mod spinlock;
|
||||
pub mod spinlock_mutex;
|
||||
#[cfg(feature = "time-driver")]
|
||||
pub mod time_driver;
|
||||
#[cfg(feature = "_rp235x")]
|
||||
|
||||
93
embassy-rp/src/spinlock_mutex.rs
Normal file
93
embassy-rp/src/spinlock_mutex.rs
Normal file
@ -0,0 +1,93 @@
|
||||
//! Mutex implementation utilizing an hardware spinlock
|
||||
|
||||
use core::marker::PhantomData;
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
use embassy_sync::blocking_mutex::raw::RawMutex;
|
||||
|
||||
use crate::spinlock::{Spinlock, SpinlockValid};
|
||||
|
||||
/// A mutex that allows borrowing data across executors and interrupts by utilizing an hardware spinlock
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This mutex is safe to share between different executors and interrupts.
|
||||
pub struct SpinlockRawMutex<const N: usize> {
|
||||
_phantom: PhantomData<()>,
|
||||
}
|
||||
unsafe impl<const N: usize> Send for SpinlockRawMutex<N> {}
|
||||
unsafe impl<const N: usize> Sync for SpinlockRawMutex<N> {}
|
||||
|
||||
impl<const N: usize> SpinlockRawMutex<N> {
|
||||
/// Create a new `SpinlockRawMutex`.
|
||||
pub const fn new() -> Self {
|
||||
Self { _phantom: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<const N: usize> RawMutex for SpinlockRawMutex<N>
|
||||
where
|
||||
Spinlock<N>: SpinlockValid,
|
||||
{
|
||||
const INIT: Self = Self::new();
|
||||
|
||||
fn lock<R>(&self, f: impl FnOnce() -> R) -> R {
|
||||
// Store the initial interrupt state in stack variable
|
||||
let interrupts_active = cortex_m::register::primask::read().is_active();
|
||||
|
||||
// Spin until we get the lock
|
||||
loop {
|
||||
// Need to disable interrupts to ensure that we will not deadlock
|
||||
// if an interrupt or higher prio locks the spinlock after we acquire the lock
|
||||
cortex_m::interrupt::disable();
|
||||
// Ensure the compiler doesn't re-order accesses and violate safety here
|
||||
core::sync::atomic::compiler_fence(Ordering::SeqCst);
|
||||
if let Some(lock) = Spinlock::<N>::try_claim() {
|
||||
// We just acquired the lock.
|
||||
// 1. Forget it, so we don't immediately unlock
|
||||
core::mem::forget(lock);
|
||||
break;
|
||||
}
|
||||
// We didn't get the lock, enable interrupts if they were enabled before we started
|
||||
if interrupts_active {
|
||||
// safety: interrupts are only enabled, if they had been enabled before
|
||||
unsafe {
|
||||
cortex_m::interrupt::enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let retval = f();
|
||||
|
||||
// Ensure the compiler doesn't re-order accesses and violate safety here
|
||||
core::sync::atomic::compiler_fence(Ordering::SeqCst);
|
||||
// Release the spinlock to allow others to lock mutex again
|
||||
// safety: this point is only reached a spinlock was acquired before
|
||||
unsafe {
|
||||
Spinlock::<N>::release();
|
||||
}
|
||||
|
||||
// Re-enable interrupts if they were enabled before the mutex was locked
|
||||
if interrupts_active {
|
||||
// safety: interrupts are only enabled, if they had been enabled before
|
||||
unsafe {
|
||||
cortex_m::interrupt::enable();
|
||||
}
|
||||
}
|
||||
|
||||
retval
|
||||
}
|
||||
}
|
||||
|
||||
pub mod blocking_mutex {
|
||||
//! Mutex implementation utilizing an hardware spinlock
|
||||
use embassy_sync::blocking_mutex::Mutex;
|
||||
|
||||
use crate::spinlock_mutex::SpinlockRawMutex;
|
||||
/// A mutex that allows borrowing data across executors and interrupts by utilizing an hardware spinlock.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This mutex is safe to share between different executors and interrupts.
|
||||
pub type SpinlockMutex<const N: usize, T> = Mutex<SpinlockRawMutex<N>, T>;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user