use core::sync::atomic::{AtomicBool, Ordering};
pub struct SpinLock {
lock: AtomicBool,
}
#[must_use = "if unused, the lock will release automatically"]
pub struct SpinLockGuard<'a> {
lock: &'a AtomicBool,
}
unsafe impl Send for SpinLockGuard<'_> {}
unsafe impl Sync for SpinLockGuard<'_> {}
impl Drop for SpinLockGuard<'_> {
fn drop(&mut self) {
self.lock.store(false, Ordering::Release);
}
}
impl SpinLock {
pub const fn new() -> Self {
Self { lock: AtomicBool::new(false) }
}
pub fn try_lock(&self) -> Option<SpinLockGuard<'_>> {
if self.lock
.compare_exchange(
false,
true,
Ordering::Acquire,
Ordering::Relaxed
).is_ok()
{
Some(SpinLockGuard {
lock: &self.lock,
})
} else {
None
}
}
pub fn lock(&self) -> SpinLockGuard<'_> {
loop {
if let Some(guard) = self.try_lock() {
return guard
}
core::hint::spin_loop();
}
}
pub fn is_locked(&self) -> bool {
self.lock.load(Ordering::Relaxed)
}
}
impl Default for SpinLock {
fn default() -> Self {
Self::new()
}
}