use std::sync::atomic::Ordering;
thread_local! {
static TID: libc::pid_t = gettid();
}
#[repr(transparent)]
pub struct RawPriorityInheritingLock<S>(linux_futex::PiFutex<S>);
impl<S> RawPriorityInheritingLock<S> {
pub const fn new() -> Self {
Self(linux_futex::PiFutex::new(0))
}
}
impl<S> Default for RawPriorityInheritingLock<S> {
fn default() -> Self {
Self::new()
}
}
unsafe impl<S: linux_futex::Scope> lock_api::RawMutex for RawPriorityInheritingLock<S> {
#[allow(clippy::declare_interior_mutable_const)]
const INIT: RawPriorityInheritingLock<S> = RawPriorityInheritingLock::new();
type GuardMarker = lock_api::GuardNoSend;
fn lock(&self) {
let tid = get_cached_tid();
let fast_locked = self
.0
.value
.compare_exchange(0, tid, Ordering::SeqCst, Ordering::SeqCst);
if fast_locked.is_err() {
while self.0.lock_pi().is_err() {}
}
}
fn try_lock(&self) -> bool {
let tid = get_cached_tid();
let fast_locked = self
.0
.value
.compare_exchange(0, tid, Ordering::SeqCst, Ordering::SeqCst);
match fast_locked {
Ok(_) => true,
Err(_) => self.0.trylock_pi().is_ok(),
}
}
unsafe fn unlock(&self) {
let tid = get_cached_tid();
let fast_unlocked =
self.0
.value
.compare_exchange(tid, 0, Ordering::SeqCst, Ordering::SeqCst);
if fast_unlocked.is_err() {
self.0.unlock_pi();
}
}
}
unsafe impl<S: linux_futex::Scope> lock_api::RawMutexTimed for RawPriorityInheritingLock<S> {
type Duration = std::time::Duration;
type Instant = std::time::Instant;
fn try_lock_for(&self, timeout: Self::Duration) -> bool {
self.try_lock_until(Self::Instant::now() + timeout)
}
fn try_lock_until(&self, timeout: Self::Instant) -> bool {
let tid = get_cached_tid();
let fast_locked = self
.0
.value
.compare_exchange(0, tid, Ordering::SeqCst, Ordering::SeqCst);
if fast_locked.is_ok() {
return true;
}
loop {
match self.0.lock_pi_until(timeout) {
Ok(_) => return true,
Err(linux_futex::TimedLockError::TryAgain) => (),
Err(linux_futex::TimedLockError::TimedOut) => return false,
}
}
}
}
pub type PriorityInheritingLock<T> =
lock_api::Mutex<RawPriorityInheritingLock<linux_futex::Private>, T>;
pub type PriorityInheritingLockGuard<'a, T> =
lock_api::MutexGuard<'a, RawPriorityInheritingLock<linux_futex::Private>, T>;
pub type SharedPriorityInheritingLock<T> =
lock_api::Mutex<RawPriorityInheritingLock<linux_futex::Shared>, T>;
pub type SharedPriorityInheritingLockGuard<'a, T> =
lock_api::MutexGuard<'a, RawPriorityInheritingLock<linux_futex::Shared>, T>;
pub fn gettid() -> libc::pid_t {
unsafe { libc::gettid() }
}
#[inline]
fn get_cached_tid() -> libc::pid_t {
let mut tid = 0;
TID.with(|it| {
tid = *it;
});
tid
}