use std::cell::UnsafeCell; use std::ops::{Deref, DerefMut}; use std::sync::atomic::{AtomicBool, Ordering}; use crossbeam_utils::Backoff; /// A simple spinlock. #[derive(Debug)] pub struct Spinlock { locked: AtomicBool, value: UnsafeCell, } unsafe impl Send for Spinlock {} unsafe impl Sync for Spinlock {} impl Spinlock { /// Returns a new spinlock initialized with `value`. pub const fn new(value: T) -> Spinlock { Spinlock { locked: AtomicBool::new(false), value: UnsafeCell::new(value), } } /// Locks the spinlock. pub fn lock(&self) -> SpinlockGuard<'_, T> { let backoff = Backoff::new(); while self.locked.compare_and_swap(false, true, Ordering::Acquire) { backoff.snooze(); } SpinlockGuard { parent: self } } } /// A guard holding a spinlock locked. #[derive(Debug)] pub struct SpinlockGuard<'a, T> { parent: &'a Spinlock, } unsafe impl Send for SpinlockGuard<'_, T> {} unsafe impl Sync for SpinlockGuard<'_, T> {} impl<'a, T> Drop for SpinlockGuard<'a, T> { fn drop(&mut self) { self.parent.locked.store(false, Ordering::Release); } } impl<'a, T> Deref for SpinlockGuard<'a, T> { type Target = T; fn deref(&self) -> &T { unsafe { &*self.parent.value.get() } } } impl<'a, T> DerefMut for SpinlockGuard<'a, T> { fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.parent.value.get() } } } #[test] fn spinlock() { use std::sync::Arc; use crate::sync::{Spinlock}; use crate::task; task::block_on(async { let m = Arc::new(Spinlock::new(0)); let mut tasks = vec![]; for _ in 0..10 { let m = m.clone(); tasks.push(task::spawn(async move { *m.lock() += 1; })); } for t in tasks { t.await; } assert_eq!(*m.lock(), 10); }) }