1use crate::{MutexLike, RwLockLike};
6use fuchsia_sync::{
7 MappedMutexGuard, MappedRwLockReadGuard, MappedRwLockWriteGuard, MutexGuard, RwLockReadGuard,
8 RwLockWriteGuard,
9};
10use std::marker::PhantomData;
11
12#[cfg(feature = "detect_lock_dep_cycles")]
13mod tracking {
14 use std::cell::RefCell;
15 use std::rc::Rc;
16
17 struct HeldLock {
19 encoded_value: usize,
21 active_subclass_tokens: usize,
23 name: &'static str,
25 }
26
27 struct ThreadState {
29 held_locks: Vec<HeldLock>,
31 }
32
33 thread_local! {
34 static STATE: RefCell<ThreadState> = const { RefCell::new(ThreadState {
35 held_locks: Vec::new(),
36 }) };
37 }
38
39 #[inline(always)]
44 fn check_and_push_lock(target_value: usize, name: &'static str) {
45 STATE.with(|state| {
46 let mut s = state.borrow_mut();
47 if let Some(last) = s.held_locks.last() {
48 let last_value = last.encoded_value;
49 let last_level = last_value & !0xF;
50 let target_level = target_value & !0xF;
51
52 if target_value == last_value {
53 panic!(
54 "LockDep: Self-deadlock detected on lock '{name}' (level {target_value})!"
55 );
56 }
57 if target_level < last_level {
58 panic!(
59 "Invalid lock ordering cycle detected: attempted to acquire '{name}' \
60 after '{}' ({target_level} < {last_level})!",
61 last.name
62 );
63 }
64 if target_level == last_level {
65 if last.active_subclass_tokens == 0 {
67 panic!(
68 "LockDep: Subclassing not allowed or already consumed for lock '{}'",
69 last.name
70 );
71 }
72 }
73 }
74 s.held_locks.push(HeldLock {
75 encoded_value: target_value,
76 active_subclass_tokens: 0,
77 name,
78 });
79 });
80 }
81
82 #[inline(always)]
84 fn pop_lock(target_value: usize) {
85 STATE.with(|state| {
86 let mut s = state.borrow_mut();
87 let Some(pos) = s.held_locks.iter().rposition(|v| v.encoded_value == target_value)
88 else {
89 panic!(
90 "LockDep: Attempted to pop a tracked lock that was not tracked. \
91 Discrepancy detected. Target Lock : {target_value}"
92 );
93 };
94 let lock = &s.held_locks[pos];
95 if lock.active_subclass_tokens > 0 {
96 let stack_str = s
97 .held_locks
98 .iter()
99 .map(|v| format!("{:X}:{}", v.encoded_value, v.active_subclass_tokens))
100 .collect::<Vec<_>>()
101 .join(", ");
102 panic!(
103 "LockDep: Attempted to drop a lock with active subclass tokens! \
104 Target: {:X}, tokens: {}, Stack: [{}]",
105 target_value, lock.active_subclass_tokens, stack_str
106 );
107 }
108 s.held_locks.remove(pos);
109 });
110 }
111
112 #[cfg(test)]
113 pub fn clear_state() {
114 STATE.with(|state| state.borrow_mut().held_locks.clear());
115 }
116
117 #[inline(always)]
121 fn get_subclass(lock_id: usize) -> u8 {
122 STATE.with(|state| {
123 let s = state.borrow();
124 if let Some(last) = s.held_locks.last() {
125 let last_lock_id = last.encoded_value & !0xF;
126 if last_lock_id == lock_id && last.active_subclass_tokens > 0 {
127 return (last.encoded_value & 0xF) as u8 + 1;
128 }
129 }
130 0
131 })
132 }
133
134 #[inline(always)]
138 fn enable_subclass_for_maximal() -> usize {
139 STATE.with(|state| {
140 let mut s = state.borrow_mut();
141 if let Some(last) = s.held_locks.last_mut() {
142 last.active_subclass_tokens += 1;
143 last.encoded_value
144 } else {
145 usize::MAX
147 }
148 })
149 }
150
151 #[inline(always)]
153 fn disable_subclass(encoded_value: usize) {
154 if encoded_value == usize::MAX {
155 return;
156 }
157 STATE.with(|state| {
158 let mut s = state.borrow_mut();
159 let Some(pos) = s.held_locks.iter().rposition(|v| v.encoded_value == encoded_value)
160 else {
161 panic!(
162 "LockDep: Attempted to disable subclass for a lock that is not on the stack! \
163 Value: {:X}",
164 encoded_value
165 );
166 };
167 let lock = &mut s.held_locks[pos];
168 if lock.active_subclass_tokens == 0 {
169 panic!(
170 "LockDep: Attempted to disable subclass for a lock with no active tokens! \
171 Value: {:X}",
172 encoded_value
173 );
174 }
175 lock.active_subclass_tokens -= 1;
176 });
177 }
178
179 #[derive(Clone)]
182 pub struct LockLevelToken {
183 inner: Rc<InternalLockLevelToken>,
184 }
185
186 struct InternalLockLevelToken {
187 target_value: usize,
188 }
189
190 impl LockLevelToken {
191 pub(super) fn new(lock_id: usize, name: &'static str) -> Self {
192 let subclass = get_subclass(lock_id);
193 assert!(subclass < 16, "subclass must be between 0 and 15");
194 let target_value = lock_id | (subclass as usize & 0xF);
195 check_and_push_lock(target_value, name);
196 Self { inner: Rc::new(InternalLockLevelToken { target_value }) }
197 }
198
199 fn target_value(&self) -> usize {
200 self.inner.target_value
201 }
202 }
203
204 pub struct DynamicLockTracking {
206 lock_id: usize,
207 name: &'static str,
208 }
209
210 impl DynamicLockTracking {
211 pub(super) const fn new(lock_id: usize, name: &'static str) -> Self {
212 Self { lock_id, name }
213 }
214
215 pub(super) fn lock_id(&self) -> usize {
216 self.lock_id
217 }
218
219 pub(super) fn name(&self) -> &'static str {
220 self.name
221 }
222 }
223
224 impl Drop for InternalLockLevelToken {
225 fn drop(&mut self) {
226 pop_lock(self.target_value);
227 }
228 }
229
230 pub struct SubclassToken {
233 encoded_value: usize,
234 }
235
236 impl SubclassToken {
237 pub(super) fn new() -> Self {
238 let encoded_value = enable_subclass_for_maximal();
239 Self { encoded_value }
240 }
241 }
242
243 impl Drop for SubclassToken {
244 fn drop(&mut self) {
245 disable_subclass(self.encoded_value);
246 }
247 }
248
249 #[derive(Default)]
250 pub struct LockDepContext {
251 token: Option<LockLevelToken>,
252 }
253
254 pub(super) fn lock_with_context<'a, T>(
255 mutex: &'a crate::DynamicLockDepMutex<T>,
256 context: &mut LockDepContext,
257 ) -> crate::LockDepGuard<'a, T> {
258 match &mut context.token {
259 token @ None => {
260 let guard = mutex.lock();
261 *token = Some(guard.token.clone());
262 guard
263 }
264 Some(token) => {
265 assert_eq!(
266 mutex.tracking.lock_id(),
267 token.target_value() & !0xF,
268 "LockDep: Cannot mix different lock levels in ordered_lock_vec"
269 );
270 let inner = mutex.inner.lock();
271 crate::LockDepGuard { inner, token: token.clone() }
272 }
273 }
274 }
275
276 pub(super) fn read_with_context<'a, T>(
277 rwlock: &'a crate::DynamicLockDepRwLock<T>,
278 context: &mut LockDepContext,
279 ) -> crate::LockDepReadGuard<'a, T> {
280 match &mut context.token {
281 token @ None => {
282 let guard = rwlock.read();
283 *token = Some(guard.token.clone());
284 guard
285 }
286 Some(token) => {
287 assert_eq!(
288 rwlock.tracking.lock_id(),
289 token.target_value() & !0xF,
290 "LockDep: Cannot mix different lock levels in ordered_lock_vec"
291 );
292 let inner = rwlock.inner.read();
293 crate::LockDepReadGuard { inner, token: token.clone() }
294 }
295 }
296 }
297
298 pub(super) fn write_with_context<'a, T>(
299 rwlock: &'a crate::DynamicLockDepRwLock<T>,
300 context: &mut LockDepContext,
301 ) -> crate::LockDepWriteGuard<'a, T> {
302 match &mut context.token {
303 token @ None => {
304 let guard = rwlock.write();
305 *token = Some(guard.token.clone());
306 guard
307 }
308 Some(token) => {
309 assert_eq!(
310 rwlock.tracking.lock_id(),
311 token.target_value() & !0xF,
312 "LockDep: Cannot mix different lock levels in ordered_lock_vec"
313 );
314 let inner = rwlock.inner.write();
315 crate::LockDepWriteGuard { inner, token: token.clone() }
316 }
317 }
318 }
319}
320
321#[cfg(not(feature = "detect_lock_dep_cycles"))]
322mod tracking {
323 #[derive(Clone)]
326 pub struct LockLevelToken {}
327
328 impl LockLevelToken {
329 #[inline(always)]
330 pub(super) fn new(_lock_id: usize, _name: &'static str) -> Self {
331 Self {}
332 }
333 }
334
335 pub struct DynamicLockTracking {}
337
338 impl DynamicLockTracking {
339 pub(super) const fn new(_lock_id: usize, _name: &'static str) -> Self {
340 Self {}
341 }
342
343 pub(super) fn lock_id(&self) -> usize {
344 0
345 }
346
347 pub(super) fn name(&self) -> &'static str {
348 ""
349 }
350 }
351
352 pub struct SubclassToken {}
353
354 impl SubclassToken {
355 #[inline(always)]
356 pub(super) fn new() -> Self {
357 Self {}
358 }
359 }
360
361 pub type LockDepContext = ();
362
363 pub(super) fn lock_with_context<'a, T>(
364 mutex: &'a crate::DynamicLockDepMutex<T>,
365 _context: &mut LockDepContext,
366 ) -> crate::LockDepGuard<'a, T> {
367 mutex.lock()
368 }
369
370 pub(super) fn read_with_context<'a, T>(
371 rwlock: &'a crate::DynamicLockDepRwLock<T>,
372 _context: &mut LockDepContext,
373 ) -> crate::LockDepReadGuard<'a, T> {
374 rwlock.read()
375 }
376
377 pub(super) fn write_with_context<'a, T>(
378 rwlock: &'a crate::DynamicLockDepRwLock<T>,
379 _context: &mut LockDepContext,
380 ) -> crate::LockDepWriteGuard<'a, T> {
381 rwlock.write()
382 }
383}
384
385pub struct DynamicLockDepMutex<T> {
387 inner: fuchsia_sync::Mutex<T>,
388 tracking: tracking::DynamicLockTracking,
389}
390
391impl<T: std::fmt::Debug> std::fmt::Debug for DynamicLockDepMutex<T> {
392 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
393 write!(f, "DynamicLockDepMutex({:?})", self.inner)
394 }
395}
396
397impl<T> DynamicLockDepMutex<T> {
398 pub const fn new<L: crate::LockLevel>(value: T) -> Self {
399 Self {
400 inner: fuchsia_sync::Mutex::new(value),
401 tracking: tracking::DynamicLockTracking::new(L::LOCK_ID, L::NAME),
402 }
403 }
404
405 #[inline(always)]
406 pub fn lock(&self) -> LockDepGuard<'_, T> {
407 let token = tracking::LockLevelToken::new(self.tracking.lock_id(), self.tracking.name());
408 LockDepGuard { inner: self.inner.lock(), token }
409 }
410
411 pub fn get_mut(&mut self) -> &mut T {
416 self.inner.get_mut()
417 }
418
419 pub fn into_inner(self) -> T {
421 self.inner.into_inner()
422 }
423}
424
425impl<T> MutexLike for DynamicLockDepMutex<T> {
426 type Guard<'a>
427 = LockDepGuard<'a, T>
428 where
429 T: 'a;
430 type Context = tracking::LockDepContext;
431
432 #[inline(always)]
433 fn context() -> Self::Context {
434 Default::default()
435 }
436
437 #[inline(always)]
438 fn lock(&self, context: &mut Self::Context) -> Self::Guard<'_> {
439 tracking::lock_with_context(self, context)
440 }
441}
442
443pub struct LockDepGuard<'a, T> {
444 inner: MutexGuard<'a, T>,
445 token: tracking::LockLevelToken,
446}
447
448impl<'a, T> std::ops::Deref for LockDepGuard<'a, T> {
449 type Target = T;
450 fn deref(&self) -> &T {
451 self.inner.deref()
452 }
453}
454
455impl<'a, T> std::ops::DerefMut for LockDepGuard<'a, T> {
456 fn deref_mut(&mut self) -> &mut T {
457 self.inner.deref_mut()
458 }
459}
460
461pub struct LockDepMutex<T, L> {
463 inner: DynamicLockDepMutex<T>,
464 _level: PhantomData<L>,
465}
466
467impl<T: std::fmt::Debug, L> std::fmt::Debug for LockDepMutex<T, L> {
468 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
469 write!(f, "LockDepMutex({:?}, {})", self.inner.inner, std::any::type_name::<L>())
470 }
471}
472
473impl<T, L: crate::LockLevel> LockDepMutex<T, L> {
474 pub const fn new(value: T) -> Self {
475 Self { inner: DynamicLockDepMutex::new::<L>(value), _level: PhantomData }
476 }
477
478 #[inline(always)]
479 pub fn lock(&self) -> LockDepGuard<'_, T> {
480 self.inner.lock()
481 }
482
483 pub fn get_mut(&mut self) -> &mut T {
488 self.inner.get_mut()
489 }
490
491 pub fn into_inner(self) -> T {
493 self.inner.into_inner()
494 }
495}
496
497impl<T, L> MutexLike for LockDepMutex<T, L> {
498 type Guard<'a>
499 = LockDepGuard<'a, T>
500 where
501 T: 'a,
502 L: 'a;
503 type Context = <DynamicLockDepMutex<T> as MutexLike>::Context;
504
505 #[inline(always)]
506 fn context() -> Self::Context {
507 DynamicLockDepMutex::<T>::context()
508 }
509
510 #[inline(always)]
511 fn lock(&self, context: &mut Self::Context) -> Self::Guard<'_> {
512 MutexLike::lock(&self.inner, context)
513 }
514}
515
516impl<T, L: crate::LockLevel> From<T> for LockDepMutex<T, L> {
517 fn from(value: T) -> Self {
518 Self::new(value)
519 }
520}
521
522impl<T: Default, L: crate::LockLevel> Default for LockDepMutex<T, L> {
523 fn default() -> Self {
524 Self::new(T::default())
525 }
526}
527
528pub struct MappedLockDepGuard<'a, T: ?Sized> {
529 inner: MappedMutexGuard<'a, T>,
530 _token: tracking::LockLevelToken,
531}
532
533impl<'a, T: ?Sized> std::ops::Deref for MappedLockDepGuard<'a, T> {
534 type Target = T;
535
536 fn deref(&self) -> &Self::Target {
537 &self.inner
538 }
539}
540
541impl<'a, T: ?Sized> std::ops::DerefMut for MappedLockDepGuard<'a, T> {
542 fn deref_mut(&mut self) -> &mut Self::Target {
543 &mut self.inner
544 }
545}
546
547impl<'a, T> LockDepGuard<'a, T> {
548 pub fn map<U: ?Sized, F>(guard: Self, f: F) -> MappedLockDepGuard<'a, U>
549 where
550 F: FnOnce(&mut T) -> &mut U,
551 {
552 let token = guard.token;
553 let inner = MutexGuard::map(guard.inner, f);
554 MappedLockDepGuard { inner, _token: token }
555 }
556}
557
558pub struct DynamicLockDepRwLock<T> {
560 inner: fuchsia_sync::RwLock<T>,
561 tracking: tracking::DynamicLockTracking,
562}
563
564impl<T: std::fmt::Debug> std::fmt::Debug for DynamicLockDepRwLock<T> {
565 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
566 write!(f, "DynamicLockDepRwLock({:?})", self.inner)
567 }
568}
569
570impl<T> DynamicLockDepRwLock<T> {
571 pub const fn new<L: crate::LockLevel>(value: T) -> Self {
572 Self {
573 inner: fuchsia_sync::RwLock::new(value),
574 tracking: tracking::DynamicLockTracking::new(L::LOCK_ID, L::NAME),
575 }
576 }
577
578 #[inline(always)]
579 pub fn read(&self) -> LockDepReadGuard<'_, T> {
580 let token = tracking::LockLevelToken::new(self.tracking.lock_id(), self.tracking.name());
581 LockDepReadGuard { inner: self.inner.read(), token }
582 }
583
584 #[inline(always)]
585 pub fn write(&self) -> LockDepWriteGuard<'_, T> {
586 let token = tracking::LockLevelToken::new(self.tracking.lock_id(), self.tracking.name());
587 LockDepWriteGuard { inner: self.inner.write(), token }
588 }
589
590 pub fn get_mut(&mut self) -> &mut T {
595 self.inner.get_mut()
596 }
597
598 pub fn into_inner(self) -> T {
600 self.inner.into_inner()
601 }
602}
603
604impl<T> RwLockLike for DynamicLockDepRwLock<T> {
605 type ReadGuard<'a>
606 = LockDepReadGuard<'a, T>
607 where
608 T: 'a;
609 type WriteGuard<'a>
610 = LockDepWriteGuard<'a, T>
611 where
612 T: 'a;
613 type Context = tracking::LockDepContext;
614
615 #[inline(always)]
616 fn context() -> Self::Context {
617 Default::default()
618 }
619
620 #[inline(always)]
621 fn read(&self, context: &mut Self::Context) -> Self::ReadGuard<'_> {
622 tracking::read_with_context(self, context)
623 }
624
625 #[inline(always)]
626 fn write(&self, context: &mut Self::Context) -> Self::WriteGuard<'_> {
627 tracking::write_with_context(self, context)
628 }
629}
630
631pub struct LockDepReadGuard<'a, T> {
632 inner: RwLockReadGuard<'a, T>,
633 token: tracking::LockLevelToken,
634}
635
636impl<'a, T> std::ops::Deref for LockDepReadGuard<'a, T> {
637 type Target = T;
638 fn deref(&self) -> &T {
639 self.inner.deref()
640 }
641}
642
643pub struct LockDepWriteGuard<'a, T> {
644 inner: RwLockWriteGuard<'a, T>,
645 token: tracking::LockLevelToken,
646}
647
648impl<'a, T> std::ops::Deref for LockDepWriteGuard<'a, T> {
649 type Target = T;
650 fn deref(&self) -> &T {
651 self.inner.deref()
652 }
653}
654
655impl<'a, T> std::ops::DerefMut for LockDepWriteGuard<'a, T> {
656 fn deref_mut(&mut self) -> &mut T {
657 self.inner.deref_mut()
658 }
659}
660
661impl<'a, T> LockDepWriteGuard<'a, T> {
662 pub fn downgrade(guard: Self) -> LockDepReadGuard<'a, T> {
663 let token = guard.token;
664 let inner = RwLockWriteGuard::downgrade(guard.inner);
665 LockDepReadGuard { inner, token }
666 }
667}
668
669pub struct LockDepRwLock<T, L> {
671 inner: DynamicLockDepRwLock<T>,
672 _level: PhantomData<L>,
673}
674
675impl<T: std::fmt::Debug, L> std::fmt::Debug for LockDepRwLock<T, L> {
676 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
677 write!(f, "LockDepRwLock({:?}, {})", self.inner.inner, std::any::type_name::<L>())
678 }
679}
680
681impl<T, L: crate::LockLevel> LockDepRwLock<T, L> {
682 pub const fn new(value: T) -> Self {
683 Self { inner: DynamicLockDepRwLock::new::<L>(value), _level: PhantomData }
684 }
685
686 pub fn get_mut(&mut self) -> &mut T {
691 self.inner.get_mut()
692 }
693
694 pub fn into_inner(self) -> T {
696 self.inner.into_inner()
697 }
698
699 #[inline(always)]
700 pub fn read(&self) -> LockDepReadGuard<'_, T> {
701 self.inner.read()
702 }
703
704 #[inline(always)]
705 pub fn write(&self) -> LockDepWriteGuard<'_, T> {
706 self.inner.write()
707 }
708}
709
710impl<T, L> RwLockLike for LockDepRwLock<T, L> {
711 type ReadGuard<'a>
712 = LockDepReadGuard<'a, T>
713 where
714 T: 'a,
715 L: 'a;
716 type WriteGuard<'a>
717 = LockDepWriteGuard<'a, T>
718 where
719 T: 'a,
720 L: 'a;
721 type Context = <DynamicLockDepRwLock<T> as RwLockLike>::Context;
722
723 #[inline(always)]
724 fn context() -> Self::Context {
725 DynamicLockDepRwLock::<T>::context()
726 }
727
728 #[inline(always)]
729 fn read(&self, context: &mut Self::Context) -> Self::ReadGuard<'_> {
730 RwLockLike::read(&self.inner, context)
731 }
732
733 #[inline(always)]
734 fn write(&self, context: &mut Self::Context) -> Self::WriteGuard<'_> {
735 RwLockLike::write(&self.inner, context)
736 }
737}
738
739impl<T: Default, L: crate::LockLevel> Default for LockDepRwLock<T, L> {
740 fn default() -> Self {
741 Self::new(T::default())
742 }
743}
744
745impl<T, L: crate::LockLevel> From<T> for LockDepRwLock<T, L> {
746 fn from(value: T) -> Self {
747 Self::new(value)
748 }
749}
750
751pub struct MappedLockDepReadGuard<'a, T: ?Sized> {
752 inner: MappedRwLockReadGuard<'a, T>,
753 _token: tracking::LockLevelToken,
754}
755
756impl<'a, T: ?Sized> std::ops::Deref for MappedLockDepReadGuard<'a, T> {
757 type Target = T;
758
759 fn deref(&self) -> &Self::Target {
760 &self.inner
761 }
762}
763
764pub struct MappedLockDepWriteGuard<'a, T: ?Sized> {
765 inner: MappedRwLockWriteGuard<'a, T>,
766 _token: tracking::LockLevelToken,
767}
768
769impl<'a, T: ?Sized> std::ops::Deref for MappedLockDepWriteGuard<'a, T> {
770 type Target = T;
771
772 fn deref(&self) -> &Self::Target {
773 &self.inner
774 }
775}
776
777impl<'a, T: ?Sized> std::ops::DerefMut for MappedLockDepWriteGuard<'a, T> {
778 fn deref_mut(&mut self) -> &mut Self::Target {
779 &mut self.inner
780 }
781}
782
783impl<'a, T> LockDepReadGuard<'a, T> {
784 pub fn map<U: ?Sized, F>(guard: Self, f: F) -> MappedLockDepReadGuard<'a, U>
785 where
786 F: FnOnce(&T) -> &U,
787 {
788 let token = guard.token;
789 let inner = RwLockReadGuard::map(guard.inner, f);
790 MappedLockDepReadGuard { inner, _token: token }
791 }
792}
793
794impl<'a, T> LockDepWriteGuard<'a, T> {
795 pub fn map<U: ?Sized, F>(guard: Self, f: F) -> MappedLockDepWriteGuard<'a, U>
796 where
797 F: FnOnce(&mut T) -> &mut U,
798 {
799 let token = guard.token;
800 let inner = RwLockWriteGuard::map(guard.inner, f);
801 MappedLockDepWriteGuard { inner, _token: token }
802 }
803}
804
805pub fn allow_subclass() -> tracking::SubclassToken {
809 tracking::SubclassToken::new()
810}
811
812pub fn assert_lock_level<L: crate::LockLevel>() -> tracking::LockLevelToken {
815 tracking::LockLevelToken::new(L::LOCK_ID, L::NAME)
816}
817
818#[cfg(test)]
819#[cfg(feature = "detect_lock_dep_cycles")]
820mod tests {
821 use super::*;
822 use crate::{Unlocked, lock_ordering, ordered_lock, ordered_lock_vec};
823
824 lock_ordering! {
825 Unlocked => LevelA,
826 LevelA => LevelB,
827 }
828
829 #[test]
830 fn test_valid_lock_ordering() {
831 tracking::clear_state();
832 let lock_a: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
833 let lock_b: LockDepMutex<i32, LevelB> = LockDepMutex::new(0);
834
835 let _guard_a = lock_a.lock();
836 let _guard_b = lock_b.lock();
837 }
838
839 #[test]
840 fn test_subclass_no_lock() {
841 tracking::clear_state();
842 let _token1 = allow_subclass();
843 }
844
845 #[test]
846 fn test_valid_lock_subclass_ordering() {
847 tracking::clear_state();
848 let lock_a1: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
849 let lock_a2: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
850 let lock_a3: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
851
852 let _guard_a1 = lock_a1.lock();
853 let _token1 = allow_subclass();
854 let _guard_a2 = lock_a2.lock();
855 let _token2 = allow_subclass();
856 let _guard_a3 = lock_a3.lock();
857 }
858
859 #[test]
860 fn test_raii_subclass_guard() {
861 tracking::clear_state();
862 {
863 let lock_a1: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
864 let lock_a2: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
865
866 let _guard_a1 = lock_a1.lock();
867 let _token = allow_subclass();
868 let _guard_a2 = lock_a2.lock(); }
870 }
871
872 #[test]
873 fn test_subclass_guard_dropped_and_reacquired() {
874 tracking::clear_state();
875 {
876 let lock_a1: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
877 let lock_a2: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
878
879 let _guard_a1 = lock_a1.lock();
880 let _token1 = allow_subclass();
881 for _ in 0..2 {
882 let _guard_a2 = lock_a2.lock(); }
884 }
885 }
886
887 #[test]
888 fn test_multiple_subclass_same_level() {
889 tracking::clear_state();
890 let lock_a1: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
891 let lock_a2: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
892
893 let _guard_a1 = lock_a1.lock();
894 let _token1 = allow_subclass();
895 for _ in 0..2 {
896 let _token2 = allow_subclass();
897 let _guard_a2 = lock_a2.lock();
898 }
899 }
900
901 #[test]
902 #[should_panic(expected = "Subclassing not allowed or already consumed")]
903 fn test_raii_subclass_guard_limit() {
904 tracking::clear_state();
905 {
906 let lock_a1: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
907 let lock_a2: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
908 let lock_a3: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
909
910 let _guard_a1 = lock_a1.lock();
911 let _token = allow_subclass();
912 let _guard_a2 = lock_a2.lock();
913
914 let _guard_a3 = lock_a3.lock();
915 }
916 }
917
918 #[test]
919 fn test_raii_subclass_guard_multiple() {
920 tracking::clear_state();
921 {
922 let lock_a1: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
923 let lock_a2: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
924 let lock_a3: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
925
926 let _guard_a1 = lock_a1.lock();
927 let _token1 = allow_subclass();
928 let _guard_a2 = lock_a2.lock();
929
930 let _token2 = allow_subclass();
931 let _guard_a3 = lock_a3.lock(); }
933 }
934
935 #[test]
936 #[should_panic(expected = "Invalid lock ordering cycle detected")]
937 fn test_invalid_lock_ordering_cycle() {
938 tracking::clear_state();
939 {
940 let lock_a: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
941 let lock_b: LockDepMutex<i32, LevelB> = LockDepMutex::new(0);
942
943 let _guard_b = lock_b.lock();
944 let _guard_a = lock_a.lock(); }
946 }
947
948 #[test]
949 #[should_panic(expected = "LockDep: Self-deadlock detected")]
950 fn test_self_deadlock() {
951 tracking::clear_state();
952 {
953 let lock_a: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
954
955 let _guard_a1 = lock_a.lock();
956 let _guard_a2 = lock_a.lock();
957 }
958 }
959
960 #[test]
961 fn test_subclass_drop_out_of_order() {
962 tracking::clear_state();
963 let lock_a1: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
964 let lock_a2: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
965 let lock_a3: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
966
967 let _guard_a1 = lock_a1.lock();
968 let _token1 = allow_subclass();
969 let _guard_a2 = lock_a2.lock();
970 let _token2 = allow_subclass();
971 let _guard_a3 = lock_a3.lock();
972 std::mem::drop(_token2);
973 std::mem::drop(_guard_a2);
974 std::mem::drop(_guard_a3);
975 let _guard_a2 = lock_a2.lock();
976 }
977
978 #[test]
979 #[should_panic(expected = "LockDep: Attempted to drop a lock with active subclass tokens!")]
980 fn test_drop_lock_with_active_tokens() {
981 tracking::clear_state();
982 let lock_a: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
983 let guard = lock_a.lock();
984 let _token = allow_subclass();
985 std::mem::drop(guard);
986 }
987
988 #[test]
989 #[should_panic(
990 expected = "Invalid lock ordering cycle detected: attempted to acquire 'LevelA' after 'LevelB'"
991 )]
992 fn test_panic_message_contains_names() {
993 tracking::clear_state();
994 let lock_a: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
995 let lock_b: LockDepMutex<i32, LevelB> = LockDepMutex::new(0);
996
997 let _guard_b = lock_b.lock();
998 let _guard_a = lock_a.lock();
999 }
1000
1001 #[test]
1002 #[should_panic(expected = "Invalid lock ordering cycle detected")]
1003 fn test_assert_lock_level_panic() {
1004 tracking::clear_state();
1005 let lock_b: LockDepMutex<i32, LevelB> = LockDepMutex::new(0);
1006
1007 let _guard_b = lock_b.lock();
1008 let _token = assert_lock_level::<LevelA>();
1011 }
1012
1013 #[test]
1014 fn test_ordered_lock() {
1015 tracking::clear_state();
1016 let lock1: LockDepMutex<i32, LevelA> = LockDepMutex::new(1);
1017 let lock2: LockDepMutex<i32, LevelA> = LockDepMutex::new(2);
1018
1019 {
1020 let (g1, g2) = ordered_lock(&lock1, &lock2);
1021 assert_eq!(*g1, 1);
1022 assert_eq!(*g2, 2);
1023 }
1024
1025 {
1026 let (g2, g1) = ordered_lock(&lock2, &lock1);
1027 assert_eq!(*g1, 1);
1028 assert_eq!(*g2, 2);
1029 }
1030 }
1031
1032 #[test]
1033 fn test_ordered_lock_vec() {
1034 tracking::clear_state();
1035 let l0: LockDepMutex<i32, LevelA> = LockDepMutex::new(0);
1036 let l1: LockDepMutex<i32, LevelA> = LockDepMutex::new(1);
1037 let l2: LockDepMutex<i32, LevelA> = LockDepMutex::new(2);
1038
1039 {
1040 let guards = ordered_lock_vec(&[&l0, &l1, &l2]);
1041 assert_eq!(*guards[0], 0);
1042 assert_eq!(*guards[1], 1);
1043 assert_eq!(*guards[2], 2);
1044 }
1045
1046 {
1047 let guards = ordered_lock_vec(&[&l2, &l1, &l0]);
1048 assert_eq!(*guards[0], 2);
1049 assert_eq!(*guards[1], 1);
1050 assert_eq!(*guards[2], 0);
1051 }
1052 }
1053
1054 #[test]
1055 fn test_ordered_lock_vec_many_locks() {
1056 tracking::clear_state();
1057 let locks: Vec<LockDepMutex<i32, LevelA>> = (0..20).map(|i| LockDepMutex::new(i)).collect();
1058 let lock_refs: Vec<&LockDepMutex<i32, LevelA>> = locks.iter().collect();
1059
1060 let guards = ordered_lock_vec(&lock_refs);
1061 assert_eq!(guards.len(), 20);
1062 for i in 0..20 {
1063 assert_eq!(*guards[i], i as i32);
1064 }
1065 }
1066
1067 #[test]
1068 fn test_dynamic_lockdep_success() {
1069 tracking::clear_state();
1070 let l1 = DynamicLockDepMutex::new::<LevelA>(1);
1071 let l2 = DynamicLockDepMutex::new::<LevelB>(2);
1072 let _g1 = l1.lock();
1073 let _g2 = l2.lock();
1074 }
1075
1076 #[test]
1077 #[should_panic(expected = "Invalid lock ordering cycle detected")]
1078 fn test_dynamic_lockdep_failure() {
1079 tracking::clear_state();
1080 let l1 = DynamicLockDepMutex::new::<LevelA>(1);
1081 let l2 = DynamicLockDepMutex::new::<LevelB>(2);
1082 let _g2 = l2.lock();
1083 let _g1 = l1.lock();
1084 }
1085
1086 #[test]
1087 fn test_dynamic_lockdep_subclass() {
1088 tracking::clear_state();
1089 let l1 = DynamicLockDepMutex::new::<LevelA>(1);
1090 let l2 = DynamicLockDepMutex::new::<LevelA>(2);
1091 let _g1 = l1.lock();
1092 let _subclass = tracking::SubclassToken::new();
1093 let _g2 = l2.lock();
1094 }
1095}