1use core::sync::atomic::{AtomicU64, Ordering};
4
5mod entry;
6#[cfg(feature = "lockdep")]
7pub(in crate::sync) mod lockdep;
8mod pi_core;
9
10use self::entry::{
11 FastLockAttempt, LockEntry, capture_current_and_prepare_slow, owner_spin_eligible,
12 owner_spin_progress_gates,
13};
14pub use self::pi_core::*;
15
16pub struct RawMutex {
23 rt_lock: bool,
24 core: PiMutexCore,
25 next_waiter_sequence: AtomicU64,
26 #[cfg(feature = "lockdep")]
27 pub(crate) lockdep: super::lockdep::LockdepMap,
28}
29
30pub(in crate::sync) struct PiMutexAlgorithm<'lock> {
32 rt_lock: bool,
33 core: PiMutexCoreView<'lock>,
34 next_waiter_sequence: &'lock AtomicU64,
35}
36
37#[derive(Clone, Copy, Debug, Eq, PartialEq)]
39pub struct PiMutexLockInterrupted;
40
41impl core::fmt::Display for PiMutexLockInterrupted {
42 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
43 formatter.write_str("PI mutex wait interrupted")
44 }
45}
46
47impl core::error::Error for PiMutexLockInterrupted {}
48
49pub trait InterruptibleMutexExt<T: ?Sized> {
51 fn lock_interruptible<F>(
62 &self,
63 should_interrupt: F,
64 ) -> Result<MutexGuard<'_, T>, PiMutexLockInterrupted>
65 where
66 F: FnMut() -> bool;
67}
68
69#[cfg(not(feature = "lockdep"))]
70pub type LockSubclass = u32;
72#[cfg(feature = "lockdep")]
73pub type LockSubclass = super::lockdep::LockSubclass;
74
75pub trait LockdepMutexExt<T: ?Sized> {
77 fn lock_nested(&self, subclass: LockSubclass) -> MutexGuard<'_, T>;
79}
80
81impl<T: ?Sized> LockdepMutexExt<T> for Mutex<T> {
82 #[inline(always)]
83 #[track_caller]
84 fn lock_nested(&self, subclass: LockSubclass) -> MutexGuard<'_, T> {
85 #[cfg(not(feature = "lockdep"))]
86 {
87 let _ = subclass;
88 self.lock()
89 }
90
91 #[cfg(feature = "lockdep")]
92 {
93 let raw = unsafe { self.raw() };
95 raw.lock_nested(subclass);
96 unsafe { self.make_guard_unchecked() }
98 }
99 }
100}
101
102impl RawMutex {
103 pub const fn new() -> Self {
105 Self {
106 rt_lock: false,
107 core: PiMutexCore::new(),
108 next_waiter_sequence: AtomicU64::new(0),
109 #[cfg(feature = "lockdep")]
110 lockdep: super::lockdep::LockdepMap::new(),
111 }
112 }
113
114 pub(crate) const fn new_rt_lock() -> Self {
115 let mut lock = Self::new();
116 lock.rt_lock = true;
117 lock
118 }
119
120 const fn algorithm(&self) -> PiMutexAlgorithm<'_> {
121 let mut algorithm = PiMutexAlgorithm::new(self.core.view(), &self.next_waiter_sequence);
122 algorithm.rt_lock = self.rt_lock;
123 algorithm
124 }
125
126 pub fn is_owned_by_current(&self) -> bool {
128 self.algorithm().is_owned_by_current()
129 }
130}
131
132impl<'lock> PiMutexAlgorithm<'lock> {
133 pub(in crate::sync) const fn new(
134 core: PiMutexCoreView<'lock>,
135 next_waiter_sequence: &'lock AtomicU64,
136 ) -> Self {
137 Self {
138 rt_lock: false,
139 core,
140 next_waiter_sequence,
141 }
142 }
143
144 pub(in crate::sync) fn is_owned_by_current(&self) -> bool {
145 Self::core_is_owned_by_current(self.core)
146 }
147
148 pub(in crate::sync) fn core_is_owned_by_current(core: PiMutexCoreView<'_>) -> bool {
149 core.is_owned_by(Self::current_task_id())
150 }
151
152 #[inline(always)]
153 fn current_task_id() -> PiTaskId {
154 task_result(
155 crate::thread::current::current_thread_id(),
156 "capture current PI mutex task",
157 )
158 .into()
159 }
160
161 pub(in crate::sync) fn lock_pi(&self) {
162 if !self.rt_lock {
163 task_result(
164 crate::thread::current::validate_sleeping_lock_context(),
165 "validate sleeping lock context",
166 );
167 }
168 #[cfg(feature = "qperf-metrics")]
169 crate::diagnostics::counters::record_pi_mutex_lock_attempt();
170 match capture_current_and_prepare_slow(
171 || {
172 task_result(
173 crate::thread::current::current_thread_token(),
174 "capture current PI mutex task",
175 )
176 },
177 |current| self.try_or_observe_current_token(current.id().into()),
178 || {
179 task_result(
183 if self.rt_lock {
184 crate::thread::current::validate_rt_lock_context()
185 } else {
186 crate::thread::current::validate_blocking_context()
187 },
188 "validate PI mutex blocking context",
189 );
190 },
191 ) {
192 LockEntry::Acquired => {
193 #[cfg(feature = "qperf-metrics")]
194 crate::diagnostics::counters::record_pi_mutex_fast_acquisition();
195 }
196 LockEntry::Contended(current) => {
197 #[cfg(feature = "qperf-metrics")]
198 crate::diagnostics::counters::record_pi_mutex_slow_entry();
199 self.lock_contended(current);
200 }
201 }
202 }
203
204 fn lock_pi_interruptible(
205 &self,
206 mut should_interrupt: impl FnMut() -> bool,
207 ) -> Result<(), PiMutexLockInterrupted> {
208 task_result(
209 crate::thread::current::validate_sleeping_lock_context(),
210 "validate interruptible sleeping lock context",
211 );
212 match capture_current_and_prepare_slow(
213 || {
214 task_result(
215 crate::thread::current::current_thread_token(),
216 "capture current PI mutex task",
217 )
218 },
219 |current| self.try_or_observe_current_token(current.id().into()),
220 || {
221 task_result(
222 crate::thread::current::validate_blocking_context(),
223 "validate PI mutex blocking context",
224 );
225 },
226 ) {
227 LockEntry::Acquired => Ok(()),
228 LockEntry::Contended(current) => {
229 self.lock_contended_interruptible(current, &mut should_interrupt)
230 }
231 }
232 }
233
234 #[cold]
235 #[inline(never)]
236 fn lock_contended(&self, current: crate::thread::CurrentThreadToken) {
237 let _saved_state = self.rt_lock.then(|| {
238 task_result(
239 crate::runtime::sync::rt_lock::RtLockWaitGuard::enter(),
240 "save task state for RT lock wait",
241 )
242 });
243 let current_id = current.id().into();
244 let sequence = self.next_waiter_sequence.fetch_add(1, Ordering::Relaxed);
245 let lock = core_result(self.core.mutex_ref(), "borrow PI mutex identity");
246 let token = match task_result(
247 crate::runtime::sync::pi_mutex_lock_slow(lock, ¤t, sequence),
248 "register PI mutex waiter",
249 ) {
250 PiMutexLockResult::Acquired => {
251 #[cfg(feature = "qperf-metrics")]
252 crate::diagnostics::counters::record_pi_mutex_slow_race_acquisition();
253 return;
254 }
255 PiMutexLockResult::Waiting(token) => {
256 #[cfg(feature = "qperf-metrics")]
257 crate::diagnostics::counters::record_pi_mutex_waiter_registration();
258 token
259 }
260 };
261 debug_assert_eq!(token.thread_id(), current_id);
262 if self.try_claim_waiter(&token, ¤t) {
263 return;
264 }
265 self.wait_for_handoff(token, ¤t);
266 }
267
268 #[cold]
269 #[inline(never)]
270 fn lock_contended_interruptible(
271 &self,
272 current: crate::thread::CurrentThreadToken,
273 should_interrupt: &mut impl FnMut() -> bool,
274 ) -> Result<(), PiMutexLockInterrupted> {
275 let current_id = current.id().into();
276 let sequence = self.next_waiter_sequence.fetch_add(1, Ordering::Relaxed);
277 let lock = core_result(self.core.mutex_ref(), "borrow PI mutex identity");
278 let token = match task_result(
279 crate::runtime::sync::pi_mutex_lock_slow(lock, ¤t, sequence),
280 "register interruptible PI mutex waiter",
281 ) {
282 PiMutexLockResult::Acquired => return Ok(()),
283 PiMutexLockResult::Waiting(token) => token,
284 };
285 debug_assert_eq!(token.thread_id(), current_id);
286
287 loop {
288 if self.try_claim_waiter(&token, ¤t) {
289 return Ok(());
290 }
291 if should_interrupt() {
292 match task_result(
293 crate::runtime::sync::pi_wait_try_cancel(&token),
294 "cancel interruptible PI mutex waiter",
295 ) {
296 PiWaitCancelOutcome::Cancelled => {
297 task_result(
298 crate::runtime::sync::pi::cancel_prepared_pi_park(&token),
299 "cancel prepared interruptible PI mutex park",
300 );
301 return Err(PiMutexLockInterrupted);
302 }
303 PiWaitCancelOutcome::HandoffPending => continue,
304 }
305 }
306 if !token.can_claim() && !self.spin_on_owner(&token) {
307 task_result(
308 crate::runtime::sync::pi_park_current_once(&token),
309 "park interruptible PI mutex waiter",
310 );
311 }
312 }
313 }
314
315 fn wait_for_handoff(&self, token: PiWaitToken, current: &crate::thread::CurrentThreadToken) {
316 loop {
317 if self.try_claim_waiter(&token, current) {
318 break;
319 }
320 if !token.can_claim() && !self.spin_on_owner(&token) {
321 #[cfg(feature = "qperf-metrics")]
322 crate::diagnostics::counters::record_pi_mutex_waiter_park();
323 task_result(
324 crate::runtime::sync::pi_park_current_once(&token),
325 "park PI mutex waiter",
326 );
327 }
328 }
329 assert!(
330 self.core.is_owned_by(token.thread_id()),
331 "PI core owner must name the granted waiter"
332 );
333 }
334
335 fn spin_on_owner(&self, token: &PiWaitToken) -> bool {
341 let Some(owner) = token.initial_owner() else {
342 return token.can_claim() || token.is_granted();
343 };
344 let cpu_count = task_result(
345 crate::sched::cpu_topology_len(),
346 "capture PI mutex CPU topology",
347 );
348
349 loop {
350 if token.can_claim() || token.is_granted() {
351 return true;
352 }
353
354 let may_spin = owner_spin_eligible(cpu_count, || {
355 owner_spin_progress_gates(
356 self.core.is_owned_by(owner),
357 token.initial_owner_is_on_cpu(),
358 token.is_top_waiter(),
359 crate::runtime::task_runtime::current_preemption_pending(),
360 )
361 });
362 if !may_spin {
363 return token.can_claim() || token.is_granted();
364 }
365
366 core::hint::spin_loop();
367 }
368 }
369
370 fn try_or_observe_current_token(&self, current: PiTaskId) -> FastLockAttempt {
371 match core_result(self.core.try_acquire(current), "try PI mutex acquisition") {
372 PiMutexAcquire::Acquired => FastLockAttempt::Acquired,
373 PiMutexAcquire::Contended => FastLockAttempt::Contended,
374 }
375 }
376
377 pub(in crate::sync) fn try_lock_pi(&self) -> bool {
378 if crate::runtime::task_runtime::in_hard_irq() {
379 return false;
380 }
381 let current = Self::current_task_id();
382 match self.core.try_acquire(current) {
383 Ok(PiMutexAcquire::Acquired) => true,
384 Ok(PiMutexAcquire::Contended) | Err(PiMutexStateError::WaiterOwnsLock) => false,
385 Err(error) => panic!("try PI mutex failed: {error}"),
386 }
387 }
388
389 fn try_claim_waiter(
390 &self,
391 token: &PiWaitToken,
392 current: &crate::thread::CurrentThreadToken,
393 ) -> bool {
394 if token.is_granted() {
395 task_result(
396 crate::runtime::sync::pi::cancel_prepared_pi_park(token),
397 "cancel prepared PI mutex park after handoff",
398 );
399 return true;
400 }
401 if !token.can_claim() {
402 return false;
403 }
404 let claimed = match task_result(
405 crate::runtime::sync::pi_mutex_claim(token, current),
406 "claim ownerless PI mutex handoff",
407 ) {
408 PiMutexClaimOutcome::Claimed => true,
409 PiMutexClaimOutcome::Retry => false,
410 };
411 if claimed {
412 task_result(
413 crate::runtime::sync::pi::cancel_prepared_pi_park(token),
414 "cancel prepared PI mutex park after claim",
415 );
416 }
417 claimed
418 }
419
420 pub(in crate::sync) unsafe fn unlock_pi(&self) {
421 unsafe { Self::unlock_core(self.core) };
423 }
424
425 pub(in crate::sync) unsafe fn unlock_core(core: PiMutexCoreView<'_>) {
426 let current = Self::current_task_id();
427 match core_result(
432 unsafe { core.try_release_owned(current) },
433 "try PI mutex release",
434 ) {
435 PiMutexOwnedRelease::Released => {}
436 PiMutexOwnedRelease::Contended(owner) => {
437 #[cfg(feature = "qperf-metrics")]
438 crate::diagnostics::counters::record_pi_mutex_contended_release();
439 unsafe { Self::unlock_contended(core, owner) };
442 }
443 }
444 }
445
446 unsafe fn unlock_contended(core: PiMutexCoreView<'_>, owner: PiTaskId) {
447 let lock = core_result(core.mutex_ref(), "borrow PI mutex release identity");
448 task_result(
449 unsafe {
450 crate::runtime::sync::pi_mutex_release_owned(lock, owner.into())
453 },
454 "release contended PI mutex",
455 );
456 }
457
458 pub(in crate::sync) fn is_locked(&self) -> bool {
459 Self::core_is_locked(self.core)
460 }
461
462 pub(in crate::sync) fn core_is_locked(core: PiMutexCoreView<'_>) -> bool {
463 core.is_locked()
464 }
465}
466
467impl RawMutex {
468 fn lock_pi(&self) {
469 self.algorithm().lock_pi();
470 }
471
472 fn lock_pi_interruptible(
473 &self,
474 should_interrupt: impl FnMut() -> bool,
475 ) -> Result<(), PiMutexLockInterrupted> {
476 self.algorithm().lock_pi_interruptible(should_interrupt)
477 }
478
479 fn try_lock_pi(&self) -> bool {
480 self.algorithm().try_lock_pi()
481 }
482
483 unsafe fn unlock_pi(&self) {
484 unsafe { self.algorithm().unlock_pi() };
486 }
487
488 #[cfg(feature = "lockdep")]
489 #[track_caller]
490 fn lock_nested(&self, subclass: LockSubclass) {
491 let lockdep = lockdep::LockdepAcquire::prepare_nested(self, false, subclass);
492 self.lock_pi();
493 lockdep.finish(true);
494 }
495
496 #[cfg(feature = "lockdep")]
497 #[track_caller]
498 fn lock_interruptible_nested(
499 &self,
500 subclass: LockSubclass,
501 should_interrupt: impl FnMut() -> bool,
502 ) -> Result<(), PiMutexLockInterrupted> {
503 let lockdep = lockdep::LockdepAcquire::prepare_nested(self, false, subclass);
504 let result = self.lock_pi_interruptible(should_interrupt);
505 lockdep.finish(result.is_ok());
506 result
507 }
508
509 #[cfg(feature = "lockdep")]
510 #[track_caller]
511 fn try_lock_nested(&self, subclass: LockSubclass) -> bool {
512 let lockdep = lockdep::LockdepAcquire::prepare_nested(self, true, subclass);
513 let acquired = self.try_lock_pi();
514 lockdep.finish(acquired);
515 acquired
516 }
517}
518
519impl Default for RawMutex {
520 fn default() -> Self {
521 Self::new()
522 }
523}
524
525unsafe impl lock_api::RawMutex for RawMutex {
530 type GuardMarker = lock_api::GuardNoSend;
531
532 const INIT: Self = Self::new();
533
534 #[inline(always)]
535 #[track_caller]
536 fn lock(&self) {
537 #[cfg(feature = "lockdep")]
538 self.lock_nested(super::lockdep::DEFAULT_LOCK_SUBCLASS);
539
540 #[cfg(not(feature = "lockdep"))]
541 self.lock_pi();
542 }
543
544 #[inline(always)]
545 #[track_caller]
546 fn try_lock(&self) -> bool {
547 if crate::runtime::task_runtime::in_hard_irq() {
548 return false;
549 }
550 #[cfg(feature = "lockdep")]
551 {
552 self.try_lock_nested(super::lockdep::DEFAULT_LOCK_SUBCLASS)
553 }
554
555 #[cfg(not(feature = "lockdep"))]
556 {
557 self.try_lock_pi()
558 }
559 }
560
561 #[inline(always)]
562 unsafe fn unlock(&self) {
563 #[cfg(feature = "lockdep")]
564 lockdep::release(self);
565 unsafe { self.unlock_pi() };
568 }
569
570 #[inline(always)]
571 fn is_locked(&self) -> bool {
572 self.algorithm().is_locked()
573 }
574}
575
576#[track_caller]
577fn core_result<T>(result: Result<T, PiMutexStateError>, operation: &'static str) -> T {
578 result.unwrap_or_else(|error| panic!("{operation} failed: {error}"))
579}
580
581#[track_caller]
582pub(super) fn task_result<T, E>(result: Result<T, E>, operation: &'static str) -> T
583where
584 E: core::fmt::Display,
585{
586 result.unwrap_or_else(|error| panic!("{operation} failed: {error}"))
587}
588
589pub type Mutex<T> = lock_api::Mutex<RawMutex, T>;
591pub type MutexGuard<'a, T> = lock_api::MutexGuard<'a, RawMutex, T>;
593
594impl<T: ?Sized> InterruptibleMutexExt<T> for Mutex<T> {
595 #[track_caller]
596 fn lock_interruptible<F>(
597 &self,
598 should_interrupt: F,
599 ) -> Result<MutexGuard<'_, T>, PiMutexLockInterrupted>
600 where
601 F: FnMut() -> bool,
602 {
603 let raw = unsafe { self.raw() };
606 #[cfg(feature = "lockdep")]
607 raw.lock_interruptible_nested(super::lockdep::DEFAULT_LOCK_SUBCLASS, should_interrupt)?;
608 #[cfg(not(feature = "lockdep"))]
609 raw.lock_pi_interruptible(should_interrupt)?;
610
611 Ok(unsafe { self.make_guard_unchecked() })
613 }
614}