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 rtc;
|
||||||
pub mod spi;
|
pub mod spi;
|
||||||
mod spinlock;
|
mod spinlock;
|
||||||
|
pub mod spinlock_mutex;
|
||||||
#[cfg(feature = "time-driver")]
|
#[cfg(feature = "time-driver")]
|
||||||
pub mod time_driver;
|
pub mod time_driver;
|
||||||
#[cfg(feature = "_rp235x")]
|
#[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