1use crate::{MutexLike, RwLockLike};
6use fuchsia_rcu::RcuDroppable;
7use fuchsia_sync::{
8 MappedMutexGuard, MappedRwLockReadGuard, MappedRwLockWriteGuard, MutexGuard, RwLockReadGuard,
9 RwLockWriteGuard,
10};
11use std::marker::PhantomData;
12
13pub use tracking::LockLevelToken;
14
15#[cfg(feature = "detect_lock_dep_cycles")]
16mod tracking {
17 use fuchsia_rcu::RcuDroppable;
18 use std::cell::RefCell;
19 use std::rc::Rc;
20
21 struct HeldLock {
23 encoded_value: usize,
25 active_subclass_tokens: usize,
27 name: &'static str,
29 }
30
31 impl HeldLock {
32 fn new(encoded_value: usize, name: &'static str) -> Self {
33 Self { encoded_value, active_subclass_tokens: 0, name }
34 }
35 }
36
37 struct ThreadState {
39 held_locks: Vec<HeldLock>,
41 }
42
43 thread_local! {
44 static STATE: RefCell<ThreadState> = const { RefCell::new(ThreadState {
45 held_locks: Vec::new(),
46 }) };
47 }
48
49 #[inline(always)]
54 #[track_caller]
55 fn check_and_push_lock(lock: HeldLock) {
56 let panic_message = STATE.try_with(|state| {
57 let mut s = state.borrow_mut();
58 if let Some(last) = s.held_locks.last() {
59 let last_value = last.encoded_value;
60 let last_level = last_value & !0xF;
61 let target_value = lock.encoded_value;
62 let target_level = target_value & !0xF;
63 let name = lock.name;
64
65 if target_value == last_value {
66 if target_level == last_level && name != last.name {
67 return Err(format!(
68 "LockDep: Invalid lock ordering detected: acquired lock '{}' while holding lock '{}' (both share the same lock level {})!",
69 name, last.name, target_value
70 ));
71 } else {
72 return Err(format!(
73 "LockDep: Self-deadlock detected on lock '{name}' (level {target_value})!"
74 ));
75 }
76 }
77 if target_level < last_level {
78 return Err(format!(
79 "LockDep: Invalid lock ordering cycle detected: \
80 attempted to acquire '{name}' after '{}' \
81 ({target_level} < {last_level})!",
82 last.name
83 ));
84 }
85 if target_level == last_level {
86 if last.active_subclass_tokens == 0 {
88 return Err(format!(
89 "LockDep: Subclassing not allowed or already consumed for lock '{}'",
90 last.name
91 ));
92 }
93 }
94 }
95 s.held_locks.push(lock);
96 Ok(())
97 });
98 if let Ok(Err(panic_message)) = panic_message {
99 panic!("{panic_message}");
100 }
101 }
102
103 #[inline(always)]
105 #[track_caller]
106 fn pop_lock(target_value: usize) -> Option<HeldLock> {
107 let held_lock = STATE.try_with(|state| {
108 let mut s = state.borrow_mut();
109 let Some(pos) = s.held_locks.iter().rposition(|v| v.encoded_value == target_value)
110 else {
111 return Err(format!(
112 "LockDep: Attempted to pop a tracked lock that was not tracked. \
113 Discrepancy detected. Target Lock : {target_value}"
114 ));
115 };
116 let lock = &s.held_locks[pos];
117 if lock.active_subclass_tokens > 0 {
118 let stack_str = s
119 .held_locks
120 .iter()
121 .map(|v| format!("{:X}:{}", v.encoded_value, v.active_subclass_tokens))
122 .collect::<Vec<_>>()
123 .join(", ");
124 return Err(format!(
125 "LockDep: Attempted to drop a lock with active subclass tokens! \
126 Target: {:X}, tokens: {}, Stack: [{}]",
127 target_value, lock.active_subclass_tokens, stack_str
128 ));
129 }
130 Ok(s.held_locks.remove(pos))
131 });
132 match held_lock.ok()? {
133 Err(panic_message) => {
134 panic!("{panic_message}");
135 }
136 Ok(held_lock) => Some(held_lock),
137 }
138 }
139
140 #[cfg(test)]
141 pub fn clear_state() {
142 STATE.with(|state| state.borrow_mut().held_locks.clear());
143 }
144
145 #[inline(always)]
149 fn get_subclass(lock_id: usize) -> u8 {
150 STATE
151 .try_with(|state| {
152 let s = state.borrow();
153 if let Some(last) = s.held_locks.last() {
154 let last_lock_id = last.encoded_value & !0xF;
155 if last_lock_id == lock_id && last.active_subclass_tokens > 0 {
156 return (last.encoded_value & 0xF) as u8 + 1;
157 }
158 }
159 0
160 })
161 .unwrap_or(0)
162 }
163
164 #[inline(always)]
169 fn enable_subclass_for_maximal() -> usize {
170 STATE
171 .try_with(|state| {
172 let mut s = state.borrow_mut();
173 if let Some(last) = s.held_locks.last_mut() {
174 last.active_subclass_tokens += 1;
175 last.encoded_value
176 } else {
177 usize::MAX
179 }
180 })
181 .unwrap_or(0)
182 }
183
184 #[inline(always)]
186 #[track_caller]
187 fn disable_subclass(encoded_value: usize) {
188 if encoded_value == usize::MAX {
189 return;
190 }
191 let panic_message = STATE.try_with(|state| {
192 let mut s = state.borrow_mut();
193 let Some(pos) = s.held_locks.iter().rposition(|v| v.encoded_value == encoded_value)
194 else {
195 return Err(format!(
196 "LockDep: Attempted to disable subclass for a lock that is not on the stack! \
197 Value: {:X}",
198 encoded_value
199 ));
200 };
201 let lock = &mut s.held_locks[pos];
202 if lock.active_subclass_tokens == 0 {
203 return Err(format!(
204 "LockDep: Attempted to disable subclass for a lock with no active tokens! \
205 Value: {:X}",
206 encoded_value
207 ));
208 }
209 lock.active_subclass_tokens -= 1;
210 Ok(())
211 });
212 if let Ok(Err(panic_message)) = panic_message {
213 panic!("{panic_message}");
214 }
215 }
216
217 #[derive(Clone)]
220 pub struct LockLevelToken {
221 inner: Rc<InternalLockLevelToken>,
222 }
223
224 struct InternalLockLevelToken {
225 target_value: usize,
226 }
227
228 impl LockLevelToken {
229 #[track_caller]
230 pub(super) fn new(lock_id: usize, name: &'static str) -> Self {
231 let subclass = get_subclass(lock_id);
232 assert!(subclass < 16, "subclass must be between 0 and 15");
233 let target_value = lock_id | (subclass as usize & 0xF);
234 check_and_push_lock(HeldLock::new(target_value, name));
235 Self { inner: Rc::new(InternalLockLevelToken { target_value }) }
236 }
237
238 fn target_value(&self) -> usize {
239 self.inner.target_value
240 }
241
242 #[track_caller]
243 pub(super) fn check_maximal(&self) {
244 let panic_message = STATE.try_with(|state| {
245 if let Some(last) = state.borrow().held_locks.last() {
246 if last.encoded_value != self.inner.target_value {
247 return Err(format!(
248 "Condvar wait requires the lock to be the latest acquired lock.",
249 ));
250 }
251 }
252 Ok(())
253 });
254 if let Ok(Err(panic_message)) = panic_message {
255 panic!("{panic_message}");
256 }
257 }
258
259 pub(super) fn unlock(&self) -> UnlockedGuard {
260 UnlockedGuard::new(self.target_value())
261 }
262 }
263
264 pub struct UnlockedGuard {
267 lock: Option<HeldLock>,
268 }
269
270 impl UnlockedGuard {
271 fn new(target_value: usize) -> Self {
272 let lock = pop_lock(target_value);
273 Self { lock }
274 }
275 }
276
277 impl Drop for UnlockedGuard {
278 fn drop(&mut self) {
279 if let Some(lock) = self.lock.take() {
280 check_and_push_lock(lock);
281 }
282 }
283 }
284
285 #[derive(RcuDroppable)]
287 pub struct DynamicLockTracking {
288 lock_id: usize,
289 name: &'static str,
290 }
291
292 impl DynamicLockTracking {
293 pub(super) const fn new(lock_id: usize, name: &'static str) -> Self {
294 Self { lock_id, name }
295 }
296
297 pub(super) fn lock_id(&self) -> usize {
298 self.lock_id
299 }
300
301 pub(super) fn name(&self) -> &'static str {
302 self.name
303 }
304 }
305
306 impl Drop for InternalLockLevelToken {
307 fn drop(&mut self) {
308 pop_lock(self.target_value);
309 }
310 }
311
312 pub struct SubclassToken {
315 encoded_value: usize,
316 }
317
318 impl SubclassToken {
319 pub(super) fn new() -> Self {
320 let encoded_value = enable_subclass_for_maximal();
321 Self { encoded_value }
322 }
323 }
324
325 impl Drop for SubclassToken {
326 fn drop(&mut self) {
327 disable_subclass(self.encoded_value);
328 }
329 }
330
331 #[derive(Default)]
332 pub struct LockDepContext {
333 token: Option<LockLevelToken>,
334 }
335
336 #[track_caller]
337 pub(super) fn lock_with_context<'a, T>(
338 mutex: &'a crate::DynamicLockDepMutex<T>,
339 context: &mut LockDepContext,
340 ) -> crate::LockDepGuard<'a, T> {
341 match &mut context.token {
342 token @ None => {
343 let guard = mutex.lock();
344 *token = Some(guard.token.clone());
345 guard
346 }
347 Some(token) => {
348 assert_eq!(
349 mutex.tracking.lock_id(),
350 token.target_value() & !0xF,
351 "LockDep: Cannot mix different lock levels in ordered_lock_vec"
352 );
353 let inner = mutex.inner.lock();
354 crate::LockDepGuard { inner, token: token.clone() }
355 }
356 }
357 }
358
359 #[track_caller]
360 pub(super) fn read_with_context<'a, T>(
361 rwlock: &'a crate::DynamicLockDepRwLock<T>,
362 context: &mut LockDepContext,
363 ) -> crate::LockDepReadGuard<'a, T> {
364 match &mut context.token {
365 token @ None => {
366 let guard = rwlock.read();
367 *token = Some(guard.token.clone());
368 guard
369 }
370 Some(token) => {
371 assert_eq!(
372 rwlock.tracking.lock_id(),
373 token.target_value() & !0xF,
374 "LockDep: Cannot mix different lock levels in ordered_lock_vec"
375 );
376 let inner = rwlock.inner.read();
377 crate::LockDepReadGuard { inner, token: token.clone() }
378 }
379 }
380 }
381
382 #[track_caller]
383 pub(super) fn write_with_context<'a, T>(
384 rwlock: &'a crate::DynamicLockDepRwLock<T>,
385 context: &mut LockDepContext,
386 ) -> crate::LockDepWriteGuard<'a, T> {
387 match &mut context.token {
388 token @ None => {
389 let guard = rwlock.write();
390 *token = Some(guard.token.clone());
391 guard
392 }
393 Some(token) => {
394 assert_eq!(
395 rwlock.tracking.lock_id(),
396 token.target_value() & !0xF,
397 "LockDep: Cannot mix different lock levels in ordered_lock_vec"
398 );
399 let inner = rwlock.inner.write();
400 crate::LockDepWriteGuard { inner, token: token.clone() }
401 }
402 }
403 }
404}
405
406#[cfg(not(feature = "detect_lock_dep_cycles"))]
407mod tracking {
408 use fuchsia_rcu::RcuDroppable;
409
410 #[derive(Clone)]
413 pub struct LockLevelToken {}
414
415 impl LockLevelToken {
416 #[inline(always)]
417 pub(super) fn new(_lock_id: usize, _name: &'static str) -> Self {
418 Self {}
419 }
420
421 pub(super) fn check_maximal(&self) {}
422
423 pub(super) fn unlock(&self) -> UnlockedGuard {
424 UnlockedGuard {}
425 }
426 }
427
428 pub struct UnlockedGuard {}
433
434 #[derive(RcuDroppable)]
436 pub struct DynamicLockTracking {}
437
438 impl DynamicLockTracking {
439 pub(super) const fn new(_lock_id: usize, _name: &'static str) -> Self {
440 Self {}
441 }
442
443 pub(super) fn lock_id(&self) -> usize {
444 0
445 }
446
447 pub(super) fn name(&self) -> &'static str {
448 ""
449 }
450 }
451
452 pub struct SubclassToken {}
453
454 impl SubclassToken {
455 #[inline(always)]
456 pub(super) fn new() -> Self {
457 Self {}
458 }
459 }
460
461 pub type LockDepContext = ();
462
463 pub(super) fn lock_with_context<'a, T>(
464 mutex: &'a crate::DynamicLockDepMutex<T>,
465 _context: &mut LockDepContext,
466 ) -> crate::LockDepGuard<'a, T> {
467 mutex.lock()
468 }
469
470 pub(super) fn read_with_context<'a, T>(
471 rwlock: &'a crate::DynamicLockDepRwLock<T>,
472 _context: &mut LockDepContext,
473 ) -> crate::LockDepReadGuard<'a, T> {
474 rwlock.read()
475 }
476
477 pub(super) fn write_with_context<'a, T>(
478 rwlock: &'a crate::DynamicLockDepRwLock<T>,
479 _context: &mut LockDepContext,
480 ) -> crate::LockDepWriteGuard<'a, T> {
481 rwlock.write()
482 }
483}
484
485#[derive(RcuDroppable)]
487pub struct DynamicLockDepMutex<T> {
488 inner: fuchsia_sync::Mutex<T>,
489 tracking: tracking::DynamicLockTracking,
490}
491
492impl<T: std::fmt::Debug> std::fmt::Debug for DynamicLockDepMutex<T> {
493 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
494 write!(f, "DynamicLockDepMutex({:?})", self.inner)
495 }
496}
497
498impl<T> DynamicLockDepMutex<T> {
499 pub const fn new<L: crate::LockLevel>(value: T) -> Self {
500 Self {
501 inner: fuchsia_sync::Mutex::new(value),
502 tracking: tracking::DynamicLockTracking::new(L::LOCK_ID, L::NAME),
503 }
504 }
505
506 #[inline(always)]
507 #[track_caller]
508 pub fn lock(&self) -> LockDepGuard<'_, T> {
509 let token = tracking::LockLevelToken::new(self.tracking.lock_id(), self.tracking.name());
510 LockDepGuard { inner: self.inner.lock(), token }
511 }
512
513 #[inline(always)]
514 #[track_caller]
515 pub fn try_lock(&self) -> Option<LockDepGuard<'_, T>> {
516 let inner = self.inner.try_lock()?;
517 let token = tracking::LockLevelToken::new(self.tracking.lock_id(), self.tracking.name());
518 Some(LockDepGuard { inner, token })
519 }
520
521 pub fn get_mut(&mut self) -> &mut T {
526 self.inner.get_mut()
527 }
528
529 pub fn into_inner(self) -> T {
531 self.inner.into_inner()
532 }
533}
534
535impl<T> MutexLike for DynamicLockDepMutex<T> {
536 type Guard<'a>
537 = LockDepGuard<'a, T>
538 where
539 T: 'a;
540 type Context = tracking::LockDepContext;
541
542 #[inline(always)]
543 fn context() -> Self::Context {
544 Default::default()
545 }
546
547 #[inline(always)]
548 fn lock(&self, context: &mut Self::Context) -> Self::Guard<'_> {
549 tracking::lock_with_context(self, context)
550 }
551}
552
553pub struct LockDepGuard<'a, T> {
554 inner: MutexGuard<'a, T>,
555 token: tracking::LockLevelToken,
556}
557
558impl<'a, T> std::ops::Deref for LockDepGuard<'a, T> {
559 type Target = T;
560 fn deref(&self) -> &T {
561 self.inner.deref()
562 }
563}
564
565impl<'a, T> std::ops::DerefMut for LockDepGuard<'a, T> {
566 fn deref_mut(&mut self) -> &mut T {
567 self.inner.deref_mut()
568 }
569}
570
571impl<'a, T> LockDepGuard<'a, T> {
572 pub(super) fn check_maximal(&self) {
573 self.token.check_maximal();
574 }
575
576 pub fn unlocked<F, U>(s: &mut Self, f: F) -> U
578 where
579 F: FnOnce() -> U,
580 {
581 let _guard = s.token.unlock();
582 MutexGuard::unlocked(&mut s.inner, f)
583 }
584}
585
586impl<'a, T> crate::condvar::WaitableMutexGuard<'a, T> for LockDepGuard<'a, T> {
587 fn inner_guard(&mut self, _token: crate::condvar::WaitToken) -> &mut MutexGuard<'a, T> {
588 self.check_maximal();
589 &mut self.inner
590 }
591}
592
593#[derive(RcuDroppable)]
595pub struct LockDepMutex<T, L> {
596 inner: DynamicLockDepMutex<T>,
597 _level: PhantomData<L>,
598}
599
600impl<T: std::fmt::Debug, L> std::fmt::Debug for LockDepMutex<T, L> {
601 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
602 write!(f, "LockDepMutex({:?}, {})", self.inner.inner, std::any::type_name::<L>())
603 }
604}
605
606impl<T, L: crate::LockLevel> LockDepMutex<T, L> {
607 pub const fn new(value: T) -> Self {
608 Self { inner: DynamicLockDepMutex::new::<L>(value), _level: PhantomData }
609 }
610
611 #[inline(always)]
612 #[track_caller]
613 pub fn lock(&self) -> LockDepGuard<'_, T> {
614 self.inner.lock()
615 }
616
617 #[inline(always)]
618 #[track_caller]
619 pub fn try_lock(&self) -> Option<LockDepGuard<'_, T>> {
620 self.inner.try_lock()
621 }
622
623 pub fn get_mut(&mut self) -> &mut T {
628 self.inner.get_mut()
629 }
630
631 pub fn into_inner(self) -> T {
633 self.inner.into_inner()
634 }
635}
636
637impl<T, L> MutexLike for LockDepMutex<T, L> {
638 type Guard<'a>
639 = LockDepGuard<'a, T>
640 where
641 T: 'a,
642 L: 'a;
643 type Context = <DynamicLockDepMutex<T> as MutexLike>::Context;
644
645 #[inline(always)]
646 fn context() -> Self::Context {
647 DynamicLockDepMutex::<T>::context()
648 }
649
650 #[inline(always)]
651 fn lock(&self, context: &mut Self::Context) -> Self::Guard<'_> {
652 MutexLike::lock(&self.inner, context)
653 }
654}
655
656impl<T, L: crate::LockLevel> From<T> for LockDepMutex<T, L> {
657 fn from(value: T) -> Self {
658 Self::new(value)
659 }
660}
661
662impl<T: Default, L: crate::LockLevel> Default for LockDepMutex<T, L> {
663 fn default() -> Self {
664 Self::new(T::default())
665 }
666}
667
668pub struct MappedLockDepGuard<'a, T: ?Sized> {
669 inner: MappedMutexGuard<'a, T>,
670 _token: tracking::LockLevelToken,
671}
672
673impl<'a, T: ?Sized> std::ops::Deref for MappedLockDepGuard<'a, T> {
674 type Target = T;
675
676 fn deref(&self) -> &Self::Target {
677 &self.inner
678 }
679}
680
681impl<'a, T: ?Sized> std::ops::DerefMut for MappedLockDepGuard<'a, T> {
682 fn deref_mut(&mut self) -> &mut Self::Target {
683 &mut self.inner
684 }
685}
686
687impl<'a, T> LockDepGuard<'a, T> {
688 pub fn map<U: ?Sized, F>(guard: Self, f: F) -> MappedLockDepGuard<'a, U>
689 where
690 F: FnOnce(&mut T) -> &mut U,
691 {
692 let token = guard.token;
693 let inner = MutexGuard::map(guard.inner, f);
694 MappedLockDepGuard { inner, _token: token }
695 }
696}
697
698#[derive(RcuDroppable)]
700pub struct DynamicLockDepRwLock<T> {
701 inner: fuchsia_sync::RwLock<T>,
702 tracking: tracking::DynamicLockTracking,
703}
704
705impl<T: std::fmt::Debug> std::fmt::Debug for DynamicLockDepRwLock<T> {
706 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
707 write!(f, "DynamicLockDepRwLock({:?})", self.inner)
708 }
709}
710
711impl<T> DynamicLockDepRwLock<T> {
712 pub const fn new<L: crate::LockLevel>(value: T) -> Self {
713 Self {
714 inner: fuchsia_sync::RwLock::new(value),
715 tracking: tracking::DynamicLockTracking::new(L::LOCK_ID, L::NAME),
716 }
717 }
718
719 #[inline(always)]
720 #[track_caller]
721 pub fn read(&self) -> LockDepReadGuard<'_, T> {
722 let token = tracking::LockLevelToken::new(self.tracking.lock_id(), self.tracking.name());
723 LockDepReadGuard { inner: self.inner.read(), token }
724 }
725
726 #[inline(always)]
727 #[track_caller]
728 pub fn try_read(&self) -> Option<LockDepReadGuard<'_, T>> {
729 let inner = self.inner.try_read()?;
730 let token = tracking::LockLevelToken::new(self.tracking.lock_id(), self.tracking.name());
731 Some(LockDepReadGuard { inner, token })
732 }
733
734 #[inline(always)]
735 #[track_caller]
736 pub fn write(&self) -> LockDepWriteGuard<'_, T> {
737 let token = tracking::LockLevelToken::new(self.tracking.lock_id(), self.tracking.name());
738 LockDepWriteGuard { inner: self.inner.write(), token }
739 }
740
741 #[inline(always)]
742 #[track_caller]
743 pub fn try_write(&self) -> Option<LockDepWriteGuard<'_, T>> {
744 let inner = self.inner.try_write()?;
745 let token = tracking::LockLevelToken::new(self.tracking.lock_id(), self.tracking.name());
746 Some(LockDepWriteGuard { inner, token })
747 }
748
749 pub fn get_mut(&mut self) -> &mut T {
754 self.inner.get_mut()
755 }
756
757 pub fn into_inner(self) -> T {
759 self.inner.into_inner()
760 }
761}
762
763impl<T> RwLockLike for DynamicLockDepRwLock<T> {
764 type ReadGuard<'a>
765 = LockDepReadGuard<'a, T>
766 where
767 T: 'a;
768 type WriteGuard<'a>
769 = LockDepWriteGuard<'a, T>
770 where
771 T: 'a;
772 type Context = tracking::LockDepContext;
773
774 #[inline(always)]
775 fn context() -> Self::Context {
776 Default::default()
777 }
778
779 #[inline(always)]
780 fn read(&self, context: &mut Self::Context) -> Self::ReadGuard<'_> {
781 tracking::read_with_context(self, context)
782 }
783
784 #[inline(always)]
785 fn write(&self, context: &mut Self::Context) -> Self::WriteGuard<'_> {
786 tracking::write_with_context(self, context)
787 }
788}
789
790pub struct LockDepReadGuard<'a, T> {
791 inner: RwLockReadGuard<'a, T>,
792 token: tracking::LockLevelToken,
793}
794
795impl<'a, T> std::ops::Deref for LockDepReadGuard<'a, T> {
796 type Target = T;
797 fn deref(&self) -> &T {
798 self.inner.deref()
799 }
800}
801
802pub struct LockDepWriteGuard<'a, T> {
803 inner: RwLockWriteGuard<'a, T>,
804 token: tracking::LockLevelToken,
805}
806
807impl<'a, T> std::ops::Deref for LockDepWriteGuard<'a, T> {
808 type Target = T;
809 fn deref(&self) -> &T {
810 self.inner.deref()
811 }
812}
813
814impl<'a, T> std::ops::DerefMut for LockDepWriteGuard<'a, T> {
815 fn deref_mut(&mut self) -> &mut T {
816 self.inner.deref_mut()
817 }
818}
819
820impl<'a, T> LockDepWriteGuard<'a, T> {
821 pub fn downgrade(guard: Self) -> LockDepReadGuard<'a, T> {
822 let token = guard.token;
823 let inner = RwLockWriteGuard::downgrade(guard.inner);
824 LockDepReadGuard { inner, token }
825 }
826}
827
828#[derive(RcuDroppable)]
830pub struct LockDepRwLock<T, L> {
831 inner: DynamicLockDepRwLock<T>,
832 _level: PhantomData<L>,
833}
834
835impl<T: std::fmt::Debug, L> std::fmt::Debug for LockDepRwLock<T, L> {
836 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
837 write!(f, "LockDepRwLock({:?}, {})", self.inner.inner, std::any::type_name::<L>())
838 }
839}
840
841impl<T, L: crate::LockLevel> LockDepRwLock<T, L> {
842 pub const fn new(value: T) -> Self {
843 Self { inner: DynamicLockDepRwLock::new::<L>(value), _level: PhantomData }
844 }
845
846 pub fn get_mut(&mut self) -> &mut T {
851 self.inner.get_mut()
852 }
853
854 pub fn into_inner(self) -> T {
856 self.inner.into_inner()
857 }
858
859 #[inline(always)]
860 #[track_caller]
861 pub fn read(&self) -> LockDepReadGuard<'_, T> {
862 self.inner.read()
863 }
864
865 #[inline(always)]
866 #[track_caller]
867 pub fn try_read(&self) -> Option<LockDepReadGuard<'_, T>> {
868 self.inner.try_read()
869 }
870
871 #[inline(always)]
872 #[track_caller]
873 pub fn write(&self) -> LockDepWriteGuard<'_, T> {
874 self.inner.write()
875 }
876
877 #[inline(always)]
878 #[track_caller]
879 pub fn try_write(&self) -> Option<LockDepWriteGuard<'_, T>> {
880 self.inner.try_write()
881 }
882}
883
884impl<T, L> RwLockLike for LockDepRwLock<T, L> {
885 type ReadGuard<'a>
886 = LockDepReadGuard<'a, T>
887 where
888 T: 'a,
889 L: 'a;
890 type WriteGuard<'a>
891 = LockDepWriteGuard<'a, T>
892 where
893 T: 'a,
894 L: 'a;
895 type Context = <DynamicLockDepRwLock<T> as RwLockLike>::Context;
896
897 #[inline(always)]
898 fn context() -> Self::Context {
899 DynamicLockDepRwLock::<T>::context()
900 }
901
902 #[inline(always)]
903 fn read(&self, context: &mut Self::Context) -> Self::ReadGuard<'_> {
904 RwLockLike::read(&self.inner, context)
905 }
906
907 #[inline(always)]
908 fn write(&self, context: &mut Self::Context) -> Self::WriteGuard<'_> {
909 RwLockLike::write(&self.inner, context)
910 }
911}
912
913impl<T: Default, L: crate::LockLevel> Default for LockDepRwLock<T, L> {
914 fn default() -> Self {
915 Self::new(T::default())
916 }
917}
918
919impl<T, L: crate::LockLevel> From<T> for LockDepRwLock<T, L> {
920 fn from(value: T) -> Self {
921 Self::new(value)
922 }
923}
924
925pub struct MappedLockDepReadGuard<'a, T: ?Sized> {
926 inner: MappedRwLockReadGuard<'a, T>,
927 _token: tracking::LockLevelToken,
928}
929
930impl<'a, T: ?Sized> std::ops::Deref for MappedLockDepReadGuard<'a, T> {
931 type Target = T;
932
933 fn deref(&self) -> &Self::Target {
934 &self.inner
935 }
936}
937
938pub struct MappedLockDepWriteGuard<'a, T: ?Sized> {
939 inner: MappedRwLockWriteGuard<'a, T>,
940 _token: tracking::LockLevelToken,
941}
942
943impl<'a, T: ?Sized> std::ops::Deref for MappedLockDepWriteGuard<'a, T> {
944 type Target = T;
945
946 fn deref(&self) -> &Self::Target {
947 &self.inner
948 }
949}
950
951impl<'a, T: ?Sized> std::ops::DerefMut for MappedLockDepWriteGuard<'a, T> {
952 fn deref_mut(&mut self) -> &mut Self::Target {
953 &mut self.inner
954 }
955}
956
957impl<'a, T> LockDepReadGuard<'a, T> {
958 pub fn map<U: ?Sized, F>(guard: Self, f: F) -> MappedLockDepReadGuard<'a, U>
959 where
960 F: FnOnce(&T) -> &U,
961 {
962 let token = guard.token;
963 let inner = RwLockReadGuard::map(guard.inner, f);
964 MappedLockDepReadGuard { inner, _token: token }
965 }
966}
967
968impl<'a, T> LockDepWriteGuard<'a, T> {
969 pub fn map<U: ?Sized, F>(guard: Self, f: F) -> MappedLockDepWriteGuard<'a, U>
970 where
971 F: FnOnce(&mut T) -> &mut U,
972 {
973 let token = guard.token;
974 let inner = RwLockWriteGuard::map(guard.inner, f);
975 MappedLockDepWriteGuard { inner, _token: token }
976 }
977}
978
979#[track_caller]
983pub fn allow_subclass() -> tracking::SubclassToken {
984 tracking::SubclassToken::new()
985}
986
987#[track_caller]
990pub fn assert_lock_level<L: crate::LockLevel>() -> tracking::LockLevelToken {
991 tracking::LockLevelToken::new(L::LOCK_ID, L::NAME)
992}
993
994#[cfg(test)]
995#[cfg(feature = "detect_lock_dep_cycles")]
996mod tests {
997 use super::*;
998 use crate::{lock_ordering, ordered_lock, ordered_lock_vec};
999
1000 lock_ordering! {
1001 LevelA => LevelB,
1002 Terminal(TerminalC),
1003 Terminal(TerminalD),
1004 }
1005
1006 #[test]
1007 fn test_valid_lock_ordering() {
1008 tracking::clear_state();
1009 let lock_a: LockDepMutex<i32, LevelA> = 0.into();
1010 let lock_b: LockDepMutex<i32, LevelB> = 0.into();
1011 let lock_c: LockDepMutex<i32, TerminalC> = 0.into();
1012 let lock_d: LockDepMutex<i32, TerminalD> = 0.into();
1013
1014 let _guard_a = lock_a.lock();
1015 let _guard_b = lock_b.lock();
1016
1017 {
1018 let _guard_c = lock_c.lock();
1019 }
1020 {
1021 let _guard_d = lock_d.lock();
1022 }
1023 }
1024
1025 #[test]
1026 fn test_subclass_no_lock() {
1027 tracking::clear_state();
1028 let _token1 = allow_subclass();
1029 }
1030
1031 #[test]
1032 fn test_valid_lock_subclass_ordering() {
1033 tracking::clear_state();
1034 let lock_a1: LockDepMutex<i32, LevelA> = 0.into();
1035 let lock_a2: LockDepMutex<i32, LevelA> = 0.into();
1036 let lock_a3: LockDepMutex<i32, LevelA> = 0.into();
1037
1038 let _guard_a1 = lock_a1.lock();
1039 let _token1 = allow_subclass();
1040 let _guard_a2 = lock_a2.lock();
1041 let _token2 = allow_subclass();
1042 let _guard_a3 = lock_a3.lock();
1043 }
1044
1045 #[test]
1046 fn test_raii_subclass_guard() {
1047 tracking::clear_state();
1048 {
1049 let lock_a1: LockDepMutex<i32, LevelA> = 0.into();
1050 let lock_a2: LockDepMutex<i32, LevelA> = 0.into();
1051
1052 let _guard_a1 = lock_a1.lock();
1053 let _token = allow_subclass();
1054 let _guard_a2 = lock_a2.lock(); }
1056 }
1057
1058 #[test]
1059 fn test_subclass_guard_dropped_and_reacquired() {
1060 tracking::clear_state();
1061 {
1062 let lock_a1: LockDepMutex<i32, LevelA> = 0.into();
1063 let lock_a2: LockDepMutex<i32, LevelA> = 0.into();
1064
1065 let _guard_a1 = lock_a1.lock();
1066 let _token1 = allow_subclass();
1067 for _ in 0..2 {
1068 let _guard_a2 = lock_a2.lock(); }
1070 }
1071 }
1072
1073 #[test]
1074 fn test_multiple_subclass_same_level() {
1075 tracking::clear_state();
1076 let lock_a1: LockDepMutex<i32, LevelA> = 0.into();
1077 let lock_a2: LockDepMutex<i32, LevelA> = 0.into();
1078
1079 let _guard_a1 = lock_a1.lock();
1080 let _token1 = allow_subclass();
1081 for _ in 0..2 {
1082 let _token2 = allow_subclass();
1083 let _guard_a2 = lock_a2.lock();
1084 }
1085 }
1086
1087 #[test]
1088 #[should_panic(expected = "Subclassing not allowed or already consumed")]
1089 fn test_raii_subclass_guard_limit() {
1090 tracking::clear_state();
1091 {
1092 let lock_a1: LockDepMutex<i32, LevelA> = 0.into();
1093 let lock_a2: LockDepMutex<i32, LevelA> = 0.into();
1094 let lock_a3: LockDepMutex<i32, LevelA> = 0.into();
1095
1096 let _guard_a1 = lock_a1.lock();
1097 let _token = allow_subclass();
1098 let _guard_a2 = lock_a2.lock();
1099
1100 let _guard_a3 = lock_a3.lock();
1101 }
1102 }
1103
1104 #[test]
1105 fn test_raii_subclass_guard_multiple() {
1106 tracking::clear_state();
1107 {
1108 let lock_a1: LockDepMutex<i32, LevelA> = 0.into();
1109 let lock_a2: LockDepMutex<i32, LevelA> = 0.into();
1110 let lock_a3: LockDepMutex<i32, LevelA> = 0.into();
1111
1112 let _guard_a1 = lock_a1.lock();
1113 let _token1 = allow_subclass();
1114 let _guard_a2 = lock_a2.lock();
1115
1116 let _token2 = allow_subclass();
1117 let _guard_a3 = lock_a3.lock(); }
1119 }
1120
1121 #[test]
1122 #[should_panic(expected = "Invalid lock ordering cycle detected")]
1123 fn test_invalid_lock_ordering_cycle() {
1124 tracking::clear_state();
1125 {
1126 let lock_a: LockDepMutex<i32, LevelA> = 0.into();
1127 let lock_b: LockDepMutex<i32, LevelB> = 0.into();
1128
1129 let _guard_b = lock_b.lock();
1130 let _guard_a = lock_a.lock(); }
1132 }
1133
1134 #[test]
1135 #[should_panic(expected = "LockDep: Self-deadlock detected")]
1136 fn test_self_deadlock() {
1137 tracking::clear_state();
1138 {
1139 let lock_a: LockDepMutex<i32, LevelA> = 0.into();
1140
1141 let _guard_a1 = lock_a.lock();
1142 let _guard_a2 = lock_a.lock();
1143 }
1144 }
1145
1146 #[test]
1147 #[should_panic(
1148 expected = "LockDep: Invalid lock ordering detected: acquired lock 'TerminalD' while holding lock 'TerminalC'"
1149 )]
1150 fn test_terminal_locks_self_deadlock() {
1151 tracking::clear_state();
1152 {
1153 let lock_c: LockDepMutex<i32, TerminalC> = 0.into();
1154 let lock_d: LockDepMutex<i32, TerminalD> = 0.into();
1155
1156 let _guard_c = lock_c.lock();
1157 let _guard_d = lock_d.lock();
1158 }
1159 }
1160
1161 #[test]
1162 fn test_subclass_drop_out_of_order() {
1163 tracking::clear_state();
1164 let lock_a1: LockDepMutex<i32, LevelA> = 0.into();
1165 let lock_a2: LockDepMutex<i32, LevelA> = 0.into();
1166 let lock_a3: LockDepMutex<i32, LevelA> = 0.into();
1167
1168 let _guard_a1 = lock_a1.lock();
1169 let _token1 = allow_subclass();
1170 let _guard_a2 = lock_a2.lock();
1171 let _token2 = allow_subclass();
1172 let _guard_a3 = lock_a3.lock();
1173 std::mem::drop(_token2);
1174 std::mem::drop(_guard_a2);
1175 std::mem::drop(_guard_a3);
1176 let _guard_a2 = lock_a2.lock();
1177 }
1178
1179 #[test]
1180 #[should_panic(expected = "LockDep: Attempted to drop a lock with active subclass tokens!")]
1181 fn test_drop_lock_with_active_tokens() {
1182 tracking::clear_state();
1183 let lock_a: LockDepMutex<i32, LevelA> = 0.into();
1184 let guard = lock_a.lock();
1185 let _token = allow_subclass();
1186 std::mem::drop(guard);
1187 }
1188
1189 #[test]
1190 #[should_panic(
1191 expected = "Invalid lock ordering cycle detected: attempted to acquire 'LevelA' after 'LevelB'"
1192 )]
1193 fn test_panic_message_contains_names() {
1194 tracking::clear_state();
1195 let lock_a: LockDepMutex<i32, LevelA> = 0.into();
1196 let lock_b: LockDepMutex<i32, LevelB> = 0.into();
1197
1198 let _guard_b = lock_b.lock();
1199 let _guard_a = lock_a.lock();
1200 }
1201
1202 #[test]
1203 #[should_panic(expected = "Invalid lock ordering cycle detected")]
1204 fn test_assert_lock_level_panic() {
1205 tracking::clear_state();
1206 let lock_b: LockDepMutex<i32, LevelB> = 0.into();
1207
1208 let _guard_b = lock_b.lock();
1209 let _token = assert_lock_level::<LevelA>();
1212 }
1213
1214 #[test]
1215 fn test_ordered_lock() {
1216 tracking::clear_state();
1217 let lock1: LockDepMutex<i32, LevelA> = 1.into();
1218 let lock2: LockDepMutex<i32, LevelA> = 2.into();
1219
1220 {
1221 let (g1, g2) = ordered_lock(&lock1, &lock2);
1222 assert_eq!(*g1, 1);
1223 assert_eq!(*g2, 2);
1224 }
1225
1226 {
1227 let (g2, g1) = ordered_lock(&lock2, &lock1);
1228 assert_eq!(*g1, 1);
1229 assert_eq!(*g2, 2);
1230 }
1231 }
1232
1233 #[test]
1234 fn test_ordered_lock_vec() {
1235 tracking::clear_state();
1236 let l0: LockDepMutex<i32, LevelA> = 0.into();
1237 let l1: LockDepMutex<i32, LevelA> = 1.into();
1238 let l2: LockDepMutex<i32, LevelA> = 2.into();
1239
1240 {
1241 let guards = ordered_lock_vec(&[&l0, &l1, &l2]);
1242 assert_eq!(*guards[0], 0);
1243 assert_eq!(*guards[1], 1);
1244 assert_eq!(*guards[2], 2);
1245 }
1246
1247 {
1248 let guards = ordered_lock_vec(&[&l2, &l1, &l0]);
1249 assert_eq!(*guards[0], 2);
1250 assert_eq!(*guards[1], 1);
1251 assert_eq!(*guards[2], 0);
1252 }
1253 }
1254
1255 #[test]
1256 fn test_ordered_lock_vec_many_locks() {
1257 tracking::clear_state();
1258 let locks: Vec<LockDepMutex<i32, LevelA>> = (0..20).map(|i| i.into()).collect();
1259 let lock_refs: Vec<&LockDepMutex<i32, LevelA>> = locks.iter().collect();
1260
1261 let guards = ordered_lock_vec(&lock_refs);
1262 assert_eq!(guards.len(), 20);
1263 for i in 0..20 {
1264 assert_eq!(*guards[i], i as i32);
1265 }
1266 }
1267
1268 #[test]
1269 fn test_dynamic_lockdep_success() {
1270 tracking::clear_state();
1271 let l1 = DynamicLockDepMutex::new::<LevelA>(1);
1272 let l2 = DynamicLockDepMutex::new::<LevelB>(2);
1273 let _g1 = l1.lock();
1274 let _g2 = l2.lock();
1275 }
1276
1277 #[test]
1278 #[should_panic(expected = "Invalid lock ordering cycle detected")]
1279 fn test_dynamic_lockdep_failure() {
1280 tracking::clear_state();
1281 let l1 = DynamicLockDepMutex::new::<LevelA>(1);
1282 let l2 = DynamicLockDepMutex::new::<LevelB>(2);
1283 let _g2 = l2.lock();
1284 let _g1 = l1.lock();
1285 }
1286
1287 #[test]
1288 fn test_dynamic_lockdep_subclass() {
1289 tracking::clear_state();
1290 let l1 = DynamicLockDepMutex::new::<LevelA>(1);
1291 let l2 = DynamicLockDepMutex::new::<LevelA>(2);
1292 let _g1 = l1.lock();
1293 let _subclass = tracking::SubclassToken::new();
1294 let _g2 = l2.lock();
1295 }
1296
1297 #[test]
1298 fn test_try_lock() {
1299 tracking::clear_state();
1300 let l1: LockDepMutex<i32, LevelA> = 1.into();
1301 let g1 = l1.try_lock();
1302 assert!(g1.is_some());
1303 std::thread::scope(|s| {
1304 s.spawn(|| {
1305 assert!(l1.try_lock().is_none());
1306 });
1307 });
1308
1309 let l2: LockDepRwLock<i32, LevelB> = 2.into();
1310 let g2 = l2.try_read();
1311 assert!(g2.is_some());
1312 std::thread::scope(|s| {
1313 s.spawn(|| {
1314 assert!(l2.try_read().is_some());
1315 });
1316 s.spawn(|| {
1317 assert!(l2.try_write().is_none());
1318 });
1319 });
1320 std::mem::drop(g2);
1321
1322 let g4 = l2.try_write();
1323 assert!(g4.is_some());
1324 std::thread::scope(|s| {
1325 s.spawn(|| {
1326 assert!(l2.try_read().is_none());
1327 });
1328 });
1329 }
1330
1331 #[test]
1332 #[should_panic(expected = "Invalid lock ordering cycle detected")]
1333 fn test_try_lock_ordering_failure() {
1334 tracking::clear_state();
1335 let l1: LockDepMutex<i32, LevelA> = 1.into();
1336 let l2: LockDepMutex<i32, LevelB> = 2.into();
1337
1338 let _g2 = l2.try_lock();
1339 let _g1 = l1.try_lock(); }
1341
1342 #[test]
1343 fn test_unlocked_guard_tracking() {
1344 tracking::clear_state();
1345 let lock_a: LockDepMutex<i32, LevelA> = 0.into();
1346 let lock_b: LockDepMutex<i32, LevelB> = 0.into();
1347
1348 let mut guard_b = lock_b.lock();
1349
1350 LockDepGuard::unlocked(&mut guard_b, || {
1351 let _guard_a = lock_a.lock();
1354 });
1355 }
1356
1357 #[test]
1358 fn test_unlocked_guard_reacquire() {
1359 tracking::clear_state();
1360 let lock_a: LockDepMutex<i32, LevelA> = 0.into();
1361
1362 let mut guard_a = lock_a.lock();
1363 LockDepGuard::unlocked(&mut guard_a, || {
1364 let _guard_a2 = lock_a.lock();
1366 });
1367 }
1368
1369 fn assert_rcu_droppable<T: fuchsia_rcu::RcuDroppable>() {}
1370
1371 #[test]
1372 fn test_rcu_droppable() {
1373 assert_rcu_droppable::<LevelA>();
1374 assert_rcu_droppable::<TerminalC>();
1375 assert_rcu_droppable::<DynamicLockDepMutex<i32>>();
1376 assert_rcu_droppable::<DynamicLockDepRwLock<i32>>();
1377 assert_rcu_droppable::<LockDepMutex<i32, LevelA>>();
1378 assert_rcu_droppable::<LockDepRwLock<i32, LevelA>>();
1379 }
1380}
1381
1382impl<T> fuchsia_sync::ResetDependencies for DynamicLockDepMutex<T> {
1383 #[inline(always)]
1384 unsafe fn reset_dependencies(&self) {
1385 unsafe { fuchsia_sync::ResetDependencies::reset_dependencies(&self.inner) }
1387 }
1388}
1389
1390impl<T, L> fuchsia_sync::ResetDependencies for LockDepMutex<T, L> {
1391 #[inline(always)]
1392 unsafe fn reset_dependencies(&self) {
1393 unsafe { fuchsia_sync::ResetDependencies::reset_dependencies(&self.inner) }
1395 }
1396}
1397
1398impl<T> fuchsia_sync::ResetDependencies for DynamicLockDepRwLock<T> {
1399 #[inline(always)]
1400 unsafe fn reset_dependencies(&self) {
1401 unsafe { fuchsia_sync::ResetDependencies::reset_dependencies(&self.inner) }
1403 }
1404}
1405
1406impl<T, L> fuchsia_sync::ResetDependencies for LockDepRwLock<T, L> {
1407 #[inline(always)]
1408 unsafe fn reset_dependencies(&self) {
1409 unsafe { fuchsia_sync::ResetDependencies::reset_dependencies(&self.inner) }
1411 }
1412}
1413
1414impl<T, L: crate::LockLevel> fuchsia_inspect_derive::Inspect for &LockDepMutex<T, L>
1415where
1416 for<'a> &'a mut T: fuchsia_inspect_derive::Inspect,
1417{
1418 fn iattach(
1419 self,
1420 parent: &fuchsia_inspect::Node,
1421 name: impl AsRef<str>,
1422 ) -> Result<(), fuchsia_inspect_derive::AttachError> {
1423 match self.try_lock() {
1424 Some(mut inner) => inner.iattach(parent, name),
1425 None => Err("could not get exclusive access to LockDepMutex".into()),
1426 }
1427 }
1428}