priority_inheriting_lock/
lib.rs1use std::sync::atomic::Ordering;
11
12thread_local! {
13 static TID: libc::pid_t = gettid();
14}
15
16#[repr(transparent)]
21pub struct RawPriorityInheritingLock<S>(linux_futex::PiFutex<S>);
22
23impl<S> RawPriorityInheritingLock<S> {
24 #[must_use]
26 pub const fn new() -> Self {
27 Self(linux_futex::PiFutex::new(0))
28 }
29}
30
31impl<S> Default for RawPriorityInheritingLock<S> {
32 fn default() -> Self {
34 Self::new()
35 }
36}
37
38unsafe impl<S: linux_futex::Scope> lock_api::RawMutex for RawPriorityInheritingLock<S> {
39 #[allow(clippy::declare_interior_mutable_const)]
41 const INIT: RawPriorityInheritingLock<S> = RawPriorityInheritingLock::new();
42
43 type GuardMarker = lock_api::GuardNoSend;
44
45 fn lock(&self) {
50 let tid = get_cached_tid();
51 let fast_locked =
52 self.0
53 .value
54 .compare_exchange(0, tid as u32, Ordering::SeqCst, Ordering::SeqCst);
55
56 if fast_locked.is_err() {
57 while self.0.lock_pi().is_err() {}
58 }
59 }
60
61 fn try_lock(&self) -> bool {
62 let tid = get_cached_tid();
63 let fast_locked =
64 self.0
65 .value
66 .compare_exchange(0, tid as u32, Ordering::SeqCst, Ordering::SeqCst);
67
68 match fast_locked {
69 Ok(_) => true,
70 Err(_) => self.0.trylock_pi().is_ok(),
71 }
72 }
73
74 unsafe fn unlock(&self) {
75 let tid = get_cached_tid();
76 let fast_unlocked =
77 self.0
78 .value
79 .compare_exchange(tid as u32, 0, Ordering::SeqCst, Ordering::SeqCst);
80
81 if fast_unlocked.is_err() {
82 self.0.unlock_pi();
83 }
84 }
85}
86
87unsafe impl<S: linux_futex::Scope> lock_api::RawMutexTimed for RawPriorityInheritingLock<S> {
88 type Duration = std::time::Duration;
89
90 type Instant = std::time::Instant;
91
92 fn try_lock_for(&self, timeout: Self::Duration) -> bool {
93 self.try_lock_until(Self::Instant::now() + timeout)
94 }
95
96 fn try_lock_until(&self, timeout: Self::Instant) -> bool {
97 let tid = get_cached_tid();
98 let fast_locked =
99 self.0
100 .value
101 .compare_exchange(0, tid as u32, Ordering::SeqCst, Ordering::SeqCst);
102
103 if fast_locked.is_ok() {
104 return true;
105 }
106
107 loop {
108 match self.0.lock_pi_until(timeout) {
109 Ok(_) => return true,
110 Err(linux_futex::TimedLockError::TryAgain) => (),
111 Err(linux_futex::TimedLockError::TimedOut) => return false,
112 }
113 }
114 }
115}
116
117pub type PriorityInheritingLock<T> =
121 lock_api::Mutex<RawPriorityInheritingLock<linux_futex::Private>, T>;
122
123pub type PriorityInheritingLockGuard<'a, T> =
129 lock_api::MutexGuard<'a, RawPriorityInheritingLock<linux_futex::Private>, T>;
130
131pub type SharedPriorityInheritingLock<T> =
135 lock_api::Mutex<RawPriorityInheritingLock<linux_futex::Shared>, T>;
136
137pub type SharedPriorityInheritingLockGuard<'a, T> =
143 lock_api::MutexGuard<'a, RawPriorityInheritingLock<linux_futex::Shared>, T>;
144
145#[must_use]
149pub fn gettid() -> libc::pid_t {
150 unsafe { libc::gettid() }
151}
152
153#[inline]
154fn get_cached_tid() -> libc::pid_t {
155 let mut tid = 0;
156 TID.with(|it| {
157 tid = *it;
158 });
159
160 tid
161}