Skip to content

Commit

Permalink
improve locking (#204)
Browse files Browse the repository at this point in the history
  • Loading branch information
xacrimon authored Apr 29, 2022
1 parent dbec6c1 commit 8f32487
Showing 1 changed file with 20 additions and 13 deletions.
33 changes: 20 additions & 13 deletions src/lock.rs
Original file line number Diff line number Diff line change
@@ -1,64 +1,71 @@
use lock_api::GuardSend;
use std::sync::atomic::{AtomicU32, Ordering};
use std::hint;
use std::mem;
use std::sync::atomic::{AtomicUsize, Ordering};

const EXCLUSIVE_BIT: u32 = 1 << 31;
const USIZE_BITS: usize = mem::size_of::<usize>() * 8;
const EXCLUSIVE_BIT: usize = 1 << (USIZE_BITS - 1);

pub type RwLock<T> = lock_api::RwLock<RawRwLock, T>;
pub type RwLockReadGuard<'a, T> = lock_api::RwLockReadGuard<'a, RawRwLock, T>;
pub type RwLockWriteGuard<'a, T> = lock_api::RwLockWriteGuard<'a, RawRwLock, T>;

pub struct RawRwLock {
data: AtomicU32,
data: AtomicUsize,
}

unsafe impl lock_api::RawRwLock for RawRwLock {
type GuardMarker = GuardSend;

#[allow(clippy::declare_interior_mutable_const)]
const INIT: Self = RawRwLock {
data: AtomicU32::new(0),
data: AtomicUsize::new(0),
};

fn lock_shared(&self) {
while !self.try_lock_shared() {}
while !self.try_lock_shared() {
hint::spin_loop();
}
}

fn try_lock_shared(&self) -> bool {
let x = self.data.load(Ordering::SeqCst);
let x = self.data.load(Ordering::Acquire);
if x & EXCLUSIVE_BIT != 0 {
return false;
}

let y = x + 1;
self.data
.compare_exchange(x, y, Ordering::SeqCst, Ordering::SeqCst)
.compare_exchange(x, y, Ordering::Release, Ordering::Relaxed)
.is_ok()
}

unsafe fn unlock_shared(&self) {
self.data.fetch_sub(1, Ordering::SeqCst);
self.data.fetch_sub(1, Ordering::Release);
}

fn lock_exclusive(&self) {
while !self.try_lock_exclusive() {}
while !self.try_lock_exclusive() {
hint::spin_loop();
}
}

fn try_lock_exclusive(&self) -> bool {
self.data
.compare_exchange(0, EXCLUSIVE_BIT, Ordering::SeqCst, Ordering::SeqCst)
.compare_exchange(0, EXCLUSIVE_BIT, Ordering::Release, Ordering::Relaxed)
.is_ok()
}

unsafe fn unlock_exclusive(&self) {
self.data.store(0, Ordering::SeqCst)
self.data.store(0, Ordering::Release)
}

fn is_locked(&self) -> bool {
self.data.load(Ordering::SeqCst) != 0
self.data.load(Ordering::Acquire) != 0
}

fn is_locked_exclusive(&self) -> bool {
self.data.load(Ordering::SeqCst) & EXCLUSIVE_BIT != 0
self.data.load(Ordering::Acquire) & EXCLUSIVE_BIT != 0
}
}

Expand Down

0 comments on commit 8f32487

Please sign in to comment.