rstubs/util/spin.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};
use core::sync::atomic::AtomicBool;
use core::sync::atomic::Ordering::*;
/// By the use of Spinlocks, it is possible to serialize blocks of code
/// that might run parallel on multiple CPU cores.
///
/// Synchronization is implemented using a lock variable. Once a thread enters
/// the critical area, it sets the lock variable (to a non-zero value); when
/// this thread leaves the critical area, it resets the lock variable to zero.
/// When trying to enter an already locked critical area, the trying thread
/// actively waits until the critical area is free again.
#[derive(Debug, Default)]
pub struct Spin<T> {
lock: AtomicBool,
/// Wrap the mutable data inside an unsafe cell, so that the compiler doesn't optimize it away
value: UnsafeCell<T>,
}
unsafe impl<T> Sync for Spin<T> {}
unsafe impl<T: Send> Send for Spin<T> {}
impl<T> Spin<T> {
/// Create a new spin lock, protecting `value`
pub const fn new(value: T) -> Self {
Self {
lock: AtomicBool::new(false),
value: UnsafeCell::new(value),
}
}
/// Locks the lock and returns the protected data.
///
/// The data is wrapped in a guard, that unlocks the lock if it goes out of scope.
#[must_use]
pub fn lock(&self) -> SpinGuard<T> {
while let Err(_) = self
.lock
.compare_exchange_weak(false, true, Acquire, Relaxed)
{
// pausing the cpu
core::hint::spin_loop();
}
SpinGuard { lock: self }
}
/// This is automatically called by the guard destructor.
pub unsafe fn unlock(&self) {
self.lock.store(false, Release);
}
/// If you really want to access the contents. This is not protected by race conditions!
pub unsafe fn raw(&self) -> &mut T {
&mut *self.value.get()
}
}
/// Accessor for the locks data, that unlocks if it goes out of scope.
pub struct SpinGuard<'a, T> {
lock: &'a Spin<T>,
}
impl<T> Deref for SpinGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { self.lock.raw() }
}
}
impl<T> DerefMut for SpinGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.lock.raw() }
}
}
impl<T> Drop for SpinGuard<'_, T> {
fn drop(&mut self) {
unsafe { self.lock.unlock() };
}
}