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