use core::sync::atomic::{AtomicU8, Ordering};
use crate::pac;
use crate::spinlock::Spinlock;
struct RpSpinlockCs;
critical_section::set_impl!(RpSpinlockCs);
const LOCK_UNOWNED: u8 = 0;
static LOCK_OWNER: AtomicU8 = AtomicU8::new(LOCK_UNOWNED);
const LOCK_ALREADY_OWNED: u8 = 2;
unsafe impl critical_section::Impl for RpSpinlockCs {
unsafe fn acquire() -> u8 {
RpSpinlockCs::acquire()
}
unsafe fn release(token: u8) {
RpSpinlockCs::release(token);
}
}
impl RpSpinlockCs {
unsafe fn acquire() -> u8 {
let interrupts_active = cortex_m::register::primask::read().is_active();
let core = pac::SIO.cpuid().read() as u8 + 1;
if LOCK_OWNER.load(Ordering::Acquire) == core {
LOCK_ALREADY_OWNED
} else {
loop {
cortex_m::interrupt::disable();
core::sync::atomic::compiler_fence(Ordering::SeqCst);
if let Some(lock) = Spinlock31::try_claim() {
core::mem::forget(lock);
LOCK_OWNER.store(core, Ordering::Relaxed);
break;
}
if interrupts_active {
cortex_m::interrupt::enable();
}
}
interrupts_active as _
}
}
unsafe fn release(token: u8) {
if token != LOCK_ALREADY_OWNED {
LOCK_OWNER.store(LOCK_UNOWNED, Ordering::Relaxed);
core::sync::atomic::compiler_fence(Ordering::SeqCst);
Spinlock31::release();
if token != 0 {
cortex_m::interrupt::enable();
}
}
}
}
pub(crate) type Spinlock31 = Spinlock<31>;