use core::sync::atomic::Ordering;
use crate::{
condvar::{CondVar, CondVarWake},
park::{DefaultPark, Park, ParkYield, Unpark},
};
const UNLOCKED: u8 = 0;
const LOCKED: u8 = 1;
#[cfg(feature = "std")]
pub type StdRawMutex = RawMutex<std::thread::Thread>;
pub type YieldRawMutex = RawMutex<ParkYield>;
pub struct RawMutex<T> {
condvar: CondVar<T>,
}
impl<T> Default for RawMutex<T> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<T> RawMutex<T> {
#[inline]
pub const fn new() -> Self {
RawMutex {
condvar: CondVar::zero(),
}
}
#[inline]
pub fn is_locked(&self) -> bool {
self.condvar.load(Ordering::Relaxed) == LOCKED
}
#[inline]
pub fn try_lock(&self) -> bool {
self.condvar
.optimistic_update(Ordering::Acquire, UNLOCKED, LOCKED)
}
}
impl<T> RawMutex<T>
where
T: Unpark,
{
#[inline]
pub fn lock_park(&self, park: impl Park<T>) {
if self
.condvar
.optimistic_update(Ordering::Acquire, UNLOCKED, LOCKED)
{
return;
}
self.condvar.update_wait_park(
park,
CondVarWake::None,
Ordering::Relaxed,
Ordering::Acquire,
|state| match state {
UNLOCKED => Some(LOCKED),
LOCKED | _ => None,
},
);
}
#[inline]
pub unsafe fn unlock(&self) {
self.condvar.set(CondVarWake::One, Ordering::Release, 0);
}
}
impl<T> RawMutex<T>
where
T: DefaultPark,
{
#[inline]
pub fn lock(&self) {
if self
.condvar
.optimistic_update(Ordering::Acquire, UNLOCKED, LOCKED)
{
return;
}
self.condvar.update_wait(
CondVarWake::None,
Ordering::Relaxed,
Ordering::Acquire,
|state| match state {
UNLOCKED => Some(LOCKED),
LOCKED | _ => None,
},
);
}
}
unsafe impl<T> lock_api::RawMutex for RawMutex<T>
where
T: DefaultPark,
{
type GuardMarker = lock_api::GuardSend;
const INIT: Self = Self::new();
#[inline]
fn is_locked(&self) -> bool {
self.is_locked()
}
#[inline]
fn try_lock(&self) -> bool {
self.try_lock()
}
#[inline]
fn lock(&self) {
self.lock()
}
#[inline]
unsafe fn unlock(&self) {}
}