use lock_api::{
GetThreadId, RawMutex, RawRwLock, RawRwLockDowngrade, RawRwLockRecursive, RawRwLockUpgrade,
RawRwLockUpgradeDowngrade,
};
use std::{cell::Cell, num::NonZeroUsize};
pub struct RawCellMutex {
locked: Cell<bool>,
}
unsafe impl RawMutex for RawCellMutex {
#[allow(clippy::declare_interior_mutable_const)]
const INIT: Self = RawCellMutex {
locked: Cell::new(false),
};
type GuardMarker = lock_api::GuardNoSend;
#[inline]
fn lock(&self) {
if self.is_locked() {
deadlock("", "Mutex")
}
self.locked.set(true)
}
#[inline]
fn try_lock(&self) -> bool {
if self.is_locked() {
false
} else {
self.locked.set(true);
true
}
}
unsafe fn unlock(&self) {
self.locked.set(false)
}
#[inline]
fn is_locked(&self) -> bool {
self.locked.get()
}
}
const WRITER_BIT: usize = 0b01;
const ONE_READER: usize = 0b10;
pub struct RawCellRwLock {
state: Cell<usize>,
}
impl RawCellRwLock {
#[inline]
fn is_exclusive(&self) -> bool {
self.state.get() & WRITER_BIT != 0
}
}
unsafe impl RawRwLock for RawCellRwLock {
#[allow(clippy::declare_interior_mutable_const)]
const INIT: Self = RawCellRwLock {
state: Cell::new(0),
};
type GuardMarker = <RawCellMutex as RawMutex>::GuardMarker;
#[inline]
fn lock_shared(&self) {
if !self.try_lock_shared() {
deadlock("sharedly ", "RwLock")
}
}
#[inline]
fn try_lock_shared(&self) -> bool {
self.try_lock_shared_recursive()
}
#[inline]
unsafe fn unlock_shared(&self) {
self.state.set(self.state.get() - ONE_READER)
}
#[inline]
fn lock_exclusive(&self) {
if !self.try_lock_exclusive() {
deadlock("exclusively ", "RwLock")
}
self.state.set(WRITER_BIT)
}
#[inline]
fn try_lock_exclusive(&self) -> bool {
if self.is_locked() {
false
} else {
self.state.set(WRITER_BIT);
true
}
}
unsafe fn unlock_exclusive(&self) {
self.state.set(0)
}
fn is_locked(&self) -> bool {
self.state.get() != 0
}
}
unsafe impl RawRwLockDowngrade for RawCellRwLock {
unsafe fn downgrade(&self) {
self.state.set(ONE_READER);
}
}
unsafe impl RawRwLockUpgrade for RawCellRwLock {
#[inline]
fn lock_upgradable(&self) {
if !self.try_lock_upgradable() {
deadlock("upgradably+sharedly ", "RwLock")
}
}
#[inline]
fn try_lock_upgradable(&self) -> bool {
self.try_lock_shared()
}
#[inline]
unsafe fn unlock_upgradable(&self) {
self.unlock_shared()
}
#[inline]
unsafe fn upgrade(&self) {
if !self.try_upgrade() {
deadlock("upgrade ", "RwLock")
}
}
#[inline]
unsafe fn try_upgrade(&self) -> bool {
if self.state.get() == ONE_READER {
self.state.set(WRITER_BIT);
true
} else {
false
}
}
}
unsafe impl RawRwLockUpgradeDowngrade for RawCellRwLock {
#[inline]
unsafe fn downgrade_upgradable(&self) {
}
#[inline]
unsafe fn downgrade_to_upgradable(&self) {
self.state.set(ONE_READER);
}
}
unsafe impl RawRwLockRecursive for RawCellRwLock {
#[inline]
fn lock_shared_recursive(&self) {
if !self.try_lock_shared_recursive() {
deadlock("recursively+sharedly ", "RwLock")
}
}
#[inline]
fn try_lock_shared_recursive(&self) -> bool {
if self.is_exclusive() {
false
} else if let Some(new) = self.state.get().checked_add(ONE_READER) {
self.state.set(new);
true
} else {
false
}
}
}
#[cold]
#[inline(never)]
fn deadlock(lock_kind: &str, ty: &str) -> ! {
panic!("deadlock: tried to {lock_kind}lock a Cell{ty} twice")
}
pub struct SingleThreadId(());
unsafe impl GetThreadId for SingleThreadId {
const INIT: Self = SingleThreadId(());
fn nonzero_thread_id(&self) -> NonZeroUsize {
NonZeroUsize::new(1).unwrap()
}
}