Skip to content

Instantly share code, notes, and snippets.

@thomcc
Last active April 2, 2021 10:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thomcc/100716c75c07e945a160376c3b879ba8 to your computer and use it in GitHub Desktop.
Save thomcc/100716c75c07e945a160376c3b879ba8 to your computer and use it in GitHub Desktop.
//! Note: don't use spin locks unless you're doing something
//! really strange. They only perform well on microbenchmarks.
use core::sync::atomic::{*, Ordering::*};
pub struct SpinLock(AtomicBool);
impl SpinLock {
#[inline]
pub const fn new() -> Self {
Self(AtomicBool::new(false))
}
#[inline]
pub fn try_lock(&self) -> Option<SlGuard<'_>> {
if self.try_acquire() {
Some(SlGuard(self))
} else {
None
}
}
#[inline]
pub fn lock(&self) -> SlGuard<'_> {
self.acquire();
SlGuard(self)
}
/// note: consider using `try_lock()`
#[inline]
pub fn try_acquire(&self) -> bool {
!self.0.swap(true, Acquire)
}
/// note: consider using `lock()`
#[inline]
pub fn acquire(&self) {
if self.try_acquire() {
return;
}
self.acquire_slow();
}
/// note: consider using `lock()`
#[inline]
pub fn release(&self) {
self.0.store(false, Release);
}
#[cold]
fn acquire_slow(&self) {
for i in 0.. {
if i < 10 {
for _ in 0..10usize {
core::hint::spin_loop();
}
} else {
// - or: sched_yield
// - or: SwitchToThread()/Sleep(0)
// - or: uh, some more spin loop hints.
std::thread::yield_now();
}
// fixme: fall back to futexing on contention.
if !self.0.load(Relaxed) && !self.0.swap(true, Acquire) {
return;
}
}
}
}
pub struct SlGuard<'a>(&'a SpinLock);
impl<'a> Drop for SlGuard<'a> {
#[inline]
fn drop(&mut self) {
self.0.release();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment