Skip to content

Instantly share code, notes, and snippets.

@VictorKoenders
Last active June 1, 2022 09:36
Show Gist options
  • Save VictorKoenders/ec68eda515be8c2f1a2fc731cb9d7bce to your computer and use it in GitHub Desktop.
Save VictorKoenders/ec68eda515be8c2f1a2fc731cb9d7bce to your computer and use it in GitHub Desktop.
Atomic mutex
use core::{sync::atomic::{AtomicBool, Ordering}, cell::UnsafeCell, ops::{Deref, DerefMut}};
pub struct AtomicMutex<T> {
locked: AtomicBool,
data: UnsafeCell<T>,
}
impl<T> AtomicMutex<T> {
pub const fn new(val: T) -> Self {
Self {
locked: AtomicBool::new(false),
data: UnsafeCell::new(val)
}
}
pub fn lock<'a>(&'a self) -> AtomicMutexGuard<'a, T> {
while self.locked.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed).is_err() {
core::hint::spin_loop();
}
AtomicMutexGuard(self)
}
}
pub struct AtomicMutexGuard<'a, T>(&'a AtomicMutex<T>);
impl<'a, T> AtomicMutexGuard<'a, T> {
pub fn copy(&self) -> T where T: Copy {
*self.deref()
}
}
impl<'a, T> Deref for AtomicMutexGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
// Safety: AtomicMutex::lock() should have ensured we only have 1 reference to this cell
unsafe { &*self.0.data.get() }
}
}
impl<'a, T> DerefMut for AtomicMutexGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
// Safety: AtomicMutex::lock() should have ensured we only have 1 reference to this cell
unsafe { &mut *self.0.data.get() }
}
}
impl<'a, T> Drop for AtomicMutexGuard<'a, T> {
fn drop(&mut self) {
self.0.locked.store(false, Ordering::Release);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment