sparreal_kernel/sync/
rwlock.rs#![allow(unused)]
use core::{
hint::spin_loop,
sync::atomic::{AtomicUsize, Ordering},
};
use lock_api::GuardSend;
use log::warn;
const READER: usize = 1 << 2;
const UPGRADED: usize = 1 << 1;
const WRITER: usize = 1;
const READERS_MASK: usize = !(WRITER | UPGRADED);
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 {
lock: AtomicUsize,
}
unsafe impl lock_api::RawRwLock for RawRwLock {
const INIT: RawRwLock = RawRwLock {
lock: AtomicUsize::new(0),
};
type GuardMarker = GuardSend;
#[inline]
fn lock_exclusive(&self) {
while !self.try_lock_exclusive() {
spin_loop();
}
}
#[inline]
fn try_lock_exclusive(&self) -> bool {
if self
.lock
.compare_exchange(0, WRITER, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
{
true
} else {
false
}
}
#[inline]
unsafe fn unlock_exclusive(&self) {
self.lock.fetch_and(!(WRITER | UPGRADED), Ordering::Release);
}
#[inline]
fn lock_shared(&self) {
while !self.try_lock_shared() {
spin_loop();
}
}
#[inline]
fn try_lock_shared(&self) -> bool {
let value = match self.acquire_reader() {
Some(v) => v,
None => return false,
};
if value & (WRITER | UPGRADED) != 0 {
self.lock.fetch_sub(READER, Ordering::Release);
false
} else {
true
}
}
#[inline]
unsafe fn unlock_shared(&self) {
self.lock.fetch_sub(READER, Ordering::Release);
}
#[inline]
fn is_locked(&self) -> bool {
let state = self.lock.load(Ordering::Relaxed);
state & (WRITER | READERS_MASK) != 0
}
#[inline]
fn is_locked_exclusive(&self) -> bool {
let state = self.lock.load(Ordering::Relaxed);
state & (WRITER) != 0
}
}
impl RawRwLock {
fn acquire_reader(&self) -> Option<usize> {
const MAX_READERS: usize = core::usize::MAX / READER / 2;
let value = self.lock.fetch_add(READER, Ordering::Acquire);
if value > MAX_READERS * READER {
self.lock.fetch_sub(READER, Ordering::Relaxed);
warn!("Too many lock readers, cannot safely proceed");
None
} else {
Some(value)
}
}
unsafe fn force_write_unlock(&self) {
debug_assert_eq!(self.lock.load(Ordering::Relaxed) & !(WRITER | UPGRADED), 0);
self.lock.fetch_and(!(WRITER | UPGRADED), Ordering::Release);
}
}