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