#![no_std]
use core::hint::spin_loop;
use core::sync::atomic::{AtomicUsize, Ordering};
use lock_api::{GuardSend, RawRwLock, RwLock};
pub struct RawPFLock {
rin: AtomicUsize,
rout: AtomicUsize,
win: AtomicUsize,
wout: AtomicUsize,
}
const RINC: usize = 0x100; const WBITS: usize = 0x3; const PRES: usize = 0x2; const PHID: usize = 0x1;
const ZERO_MASK: usize = !255usize;
unsafe impl RawRwLock for RawPFLock {
const INIT: RawPFLock = RawPFLock {
rin: AtomicUsize::new(0),
rout: AtomicUsize::new(0),
win: AtomicUsize::new(0),
wout: AtomicUsize::new(0),
};
type GuardMarker = GuardSend;
fn lock_shared(&self) {
let w = self.rin.fetch_add(RINC, Ordering::Relaxed) & WBITS;
while (w != 0) && (w == (self.rin.load(Ordering::Relaxed) & WBITS)) {
spin_loop();
}
}
unsafe fn unlock_shared(&self) {
self.rout.fetch_add(RINC, Ordering::Relaxed);
}
fn try_lock_shared(&self) -> bool {
let w = self.rin.fetch_add(RINC, Ordering::Relaxed) & WBITS;
if w == 0 || w != (self.rin.load(Ordering::Relaxed) & WBITS) {
true
} else {
self.rout.fetch_add(RINC, Ordering::Relaxed);
false
}
}
fn lock_exclusive(&self) {
let wticket = self.win.fetch_add(1, Ordering::Relaxed);
while wticket != self.wout.load(Ordering::Relaxed) {
spin_loop();
}
let w = PRES | (wticket & PHID);
let rticket = self.rin.fetch_add(w, Ordering::Relaxed);
while rticket != self.rout.load(Ordering::Relaxed) {
spin_loop();
}
}
unsafe fn unlock_exclusive(&self) {
self.rin.fetch_and(ZERO_MASK, Ordering::Relaxed);
self.wout.fetch_add(1, Ordering::Relaxed);
}
fn try_lock_exclusive(&self) -> bool {
let wticket = self.win.fetch_add(1, Ordering::Relaxed);
if wticket != self.wout.load(Ordering::Relaxed) {
self.wout.fetch_add(1, Ordering::Relaxed);
return false;
}
let w = PRES | (wticket & PHID);
let rticket = self.rin.fetch_add(w, Ordering::Relaxed);
if rticket != self.rout.load(Ordering::Relaxed) {
self.rin.fetch_and(ZERO_MASK, Ordering::Relaxed);
self.wout.fetch_add(1, Ordering::Relaxed);
return false;
}
true
}
}
pub type PFLock<T> = RwLock<RawPFLock, T>;
pub type PFLockGuard<'a, T> = lock_api::MutexGuard<'a, RawPFLock, T>;