1use crate::{DynamicLockDepMutex, LockDepGuard, LockLevel, RcuLockLevel};
6use fuchsia_rcu::{
7 RcuArc, RcuBox, RcuDroppable, RcuDroppableArc, RcuOptionArc, RcuOptionBox, RcuReadGuard,
8 RcuReadScope, RcuWeak,
9};
10use fuchsia_rcu_collections::rcu_array::RcuArray;
11use std::cell::Cell;
12use std::marker::PhantomData;
13use std::ops::Deref;
14use std::sync::{Arc, Weak};
15
16#[derive(RcuDroppable)]
24pub struct DynamicRcuLock<T> {
25 rcu: T,
26 lock: DynamicLockDepMutex<()>,
27}
28
29#[derive(RcuDroppable)]
37pub struct RcuLock<T, L = RcuLockLevel> {
38 inner: DynamicRcuLock<T>,
39 _level: PhantomData<L>,
40}
41
42pub struct RcuLockGuard<'a, T> {
45 rcu: &'a T,
46 _guard: LockDepGuard<'a, ()>,
47 _not_sync: PhantomData<Cell<()>>,
48}
49
50impl<T> DynamicRcuLock<T> {
51 pub const fn new<L: LockLevel>(rcu: T) -> Self {
53 Self { rcu, lock: DynamicLockDepMutex::new::<L>(()) }
54 }
55
56 #[inline(always)]
58 #[track_caller]
59 pub fn lock(&self) -> RcuLockGuard<'_, T> {
60 RcuLockGuard { rcu: &self.rcu, _guard: self.lock.lock(), _not_sync: PhantomData }
61 }
62
63 #[inline(always)]
65 #[track_caller]
66 pub fn try_lock(&self) -> Option<RcuLockGuard<'_, T>> {
67 Some(RcuLockGuard { rcu: &self.rcu, _guard: self.lock.try_lock()?, _not_sync: PhantomData })
68 }
69}
70
71impl<T: std::fmt::Debug> std::fmt::Debug for DynamicRcuLock<T> {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 f.debug_struct("DynamicRcuLock").field("rcu", &self.rcu).field("lock", &self.lock).finish()
74 }
75}
76
77impl<T> crate::MutexLike for DynamicRcuLock<T> {
78 type Guard<'a>
79 = RcuLockGuard<'a, T>
80 where
81 T: 'a;
82 type Context = <DynamicLockDepMutex<()> as crate::MutexLike>::Context;
83
84 #[inline(always)]
85 fn context() -> Self::Context {
86 <DynamicLockDepMutex<()> as crate::MutexLike>::context()
87 }
88
89 #[inline(always)]
90 fn lock(&self, context: &mut Self::Context) -> Self::Guard<'_> {
91 RcuLockGuard {
92 rcu: &self.rcu,
93 _guard: <DynamicLockDepMutex<()> as crate::MutexLike>::lock(&self.lock, context),
94 _not_sync: PhantomData,
95 }
96 }
97}
98
99impl<T> fuchsia_sync::ResetDependencies for DynamicRcuLock<T> {
100 #[inline(always)]
101 unsafe fn reset_dependencies(&self) {
102 unsafe { fuchsia_sync::ResetDependencies::reset_dependencies(&self.lock) }
104 }
105}
106
107impl<T, L: LockLevel> RcuLock<T, L> {
108 pub const fn new(rcu: T) -> Self {
110 Self { inner: DynamicRcuLock::new::<L>(rcu), _level: PhantomData }
111 }
112}
113
114impl<T, L> Deref for RcuLock<T, L> {
115 type Target = DynamicRcuLock<T>;
116
117 #[inline(always)]
118 fn deref(&self) -> &Self::Target {
119 &self.inner
120 }
121}
122
123impl<T: Default, L: LockLevel> Default for RcuLock<T, L> {
124 fn default() -> Self {
125 Self::new(T::default())
126 }
127}
128
129impl<T, L: LockLevel> From<T> for RcuLock<T, L> {
130 fn from(rcu: T) -> Self {
131 Self::new(rcu)
132 }
133}
134
135impl<T: std::fmt::Debug, L> std::fmt::Debug for RcuLock<T, L> {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 f.debug_struct("RcuLock")
138 .field("rcu", &self.inner.rcu)
139 .field("lock", &self.inner.lock)
140 .field("level", &std::any::type_name::<L>())
141 .finish()
142 }
143}
144
145impl<T, L> crate::MutexLike for RcuLock<T, L> {
146 type Guard<'a>
147 = RcuLockGuard<'a, T>
148 where
149 T: 'a,
150 L: 'a;
151 type Context = <DynamicRcuLock<T> as crate::MutexLike>::Context;
152
153 #[inline(always)]
154 fn context() -> Self::Context {
155 <DynamicRcuLock<T> as crate::MutexLike>::context()
156 }
157
158 #[inline(always)]
159 fn lock(&self, context: &mut Self::Context) -> Self::Guard<'_> {
160 <DynamicRcuLock<T> as crate::MutexLike>::lock(&self.inner, context)
161 }
162}
163
164impl<T, L> fuchsia_sync::ResetDependencies for RcuLock<T, L> {
165 #[inline(always)]
166 unsafe fn reset_dependencies(&self) {
167 unsafe { fuchsia_sync::ResetDependencies::reset_dependencies(&self.inner) }
169 }
170}
171
172impl<T> Deref for RcuLockGuard<'_, T> {
173 type Target = T;
174
175 #[inline(always)]
176 fn deref(&self) -> &Self::Target {
177 self.rcu
178 }
179}
180
181impl<T: std::fmt::Debug> std::fmt::Debug for RcuLockGuard<'_, T> {
182 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183 f.debug_struct("RcuLockGuard").field("rcu", &self.rcu).finish()
184 }
185}
186
187impl<T: Send + Sync + 'static> DynamicRcuLock<RcuArc<T>> {
188 pub fn upgrade(&self) -> Option<Arc<T>> {
192 self.rcu.upgrade()
193 }
194
195 pub fn is_some(&self) -> bool {
197 self.rcu.is_some()
198 }
199
200 pub fn is_none(&self) -> bool {
202 self.rcu.is_none()
203 }
204}
205
206impl<T: RcuDroppable + Sync> DynamicRcuLock<RcuArray<T>> {
207 pub fn get<'a>(&self, scope: &'a RcuReadScope, index: usize) -> Option<&'a T> {
209 self.rcu.get(scope, index)
210 }
211
212 pub fn as_slice<'a>(&self, scope: &'a RcuReadScope) -> &'a [T] {
214 self.rcu.as_slice(scope)
215 }
216}
217
218impl<T: RcuDroppable + Sync> RcuLockGuard<'_, RcuArray<T>> {
219 pub fn ensure_at_least(&self, requested_size: usize)
222 where
223 T: Clone + Default,
224 {
225 unsafe { self.rcu.ensure_at_least(requested_size) };
228 }
229}
230
231impl<T: RcuDroppable + Sync> DynamicRcuLock<RcuBox<T>> {
232 pub fn read(&self) -> RcuReadGuard<T> {
234 self.rcu.read()
235 }
236
237 pub fn as_ref<'a>(&self, scope: &'a RcuReadScope) -> &'a T {
239 self.rcu.as_ref(scope)
240 }
241
242 pub fn cloned(&self) -> T
244 where
245 T: Clone,
246 {
247 self.rcu.cloned()
248 }
249}
250
251impl<T: RcuDroppable + Sync> DynamicRcuLock<RcuDroppableArc<T>> {
252 pub fn read(&self) -> RcuReadGuard<T> {
254 self.rcu.read()
255 }
256
257 pub fn as_ref<'a>(&self, scope: &'a RcuReadScope) -> &'a T {
259 self.rcu.as_ref(scope)
260 }
261
262 pub fn to_arc(&self) -> Arc<T> {
264 self.rcu.to_arc()
265 }
266}
267
268impl<T: RcuDroppable + Sync> DynamicRcuLock<RcuOptionArc<T>> {
269 pub fn read(&self) -> Option<RcuReadGuard<T>> {
271 self.rcu.read()
272 }
273
274 pub fn as_ref<'a>(&self, scope: &'a RcuReadScope) -> Option<&'a T> {
276 self.rcu.as_ref(scope)
277 }
278
279 pub fn to_option_arc(&self) -> Option<Arc<T>> {
282 self.rcu.to_option_arc()
283 }
284}
285
286impl<T: RcuDroppable + Sync> DynamicRcuLock<RcuOptionBox<T>> {
287 pub fn read(&self) -> Option<RcuReadGuard<T>> {
289 self.rcu.read()
290 }
291
292 pub fn as_ref<'a>(&self, scope: &'a RcuReadScope) -> Option<&'a T> {
294 self.rcu.as_ref(scope)
295 }
296
297 pub fn is_some(&self, scope: &RcuReadScope) -> bool {
299 self.rcu.is_some(scope)
300 }
301
302 pub fn is_none(&self, scope: &RcuReadScope) -> bool {
304 self.rcu.is_none(scope)
305 }
306
307 pub fn cloned(&self) -> Option<T>
309 where
310 T: Clone,
311 {
312 self.rcu.cloned()
313 }
314}
315
316impl<T: Send + Sync + 'static> DynamicRcuLock<RcuWeak<T>> {
317 pub fn upgrade(&self) -> Option<Arc<T>> {
320 self.rcu.upgrade()
321 }
322
323 pub fn to_weak(&self) -> Weak<T> {
325 self.rcu.to_weak()
326 }
327
328 pub fn ptr_eq(&self, other: &Weak<T>) -> bool {
330 self.rcu.ptr_eq(other)
331 }
332
333 pub fn strong_count(&self, scope: &RcuReadScope) -> usize {
335 self.rcu.strong_count(scope)
336 }
337}
338
339#[cfg(test)]
340mod tests {
341 use super::*;
342 use crate::{LockDepMutex, lock_ordering, ordered_lock, ordered_lock_vec};
343 use fuchsia_rcu::rcu_run_callbacks;
344 use fuchsia_sync::ResetDependencies;
345 use std::sync::atomic::{AtomicUsize, Ordering};
346
347 lock_ordering! {
348 Unlocked => LevelA,
349 LevelA => LevelB,
350 }
351
352 struct DropCounter {
353 value: usize,
354 drops: Arc<AtomicUsize>,
355 }
356
357 impl DropCounter {
358 fn new(value: usize, drops: Arc<AtomicUsize>) -> Arc<Self> {
359 Arc::new(Self { value, drops })
360 }
361 }
362
363 impl Drop for DropCounter {
364 fn drop(&mut self) {
365 self.drops.fetch_add(1, Ordering::Relaxed);
366 }
367 }
368
369 #[::fuchsia::test]
370 fn test_rcu_lock_arc() {
371 let drops = Arc::new(AtomicUsize::new(0));
372 let cell: RcuLock<RcuArc<DropCounter>, LevelA> = RcuLock::default();
373
374 assert!(cell.is_none());
375 assert!(!cell.is_some());
376 assert!(cell.upgrade().is_none());
377
378 cell.lock().update(Some(DropCounter::new(42, drops.clone())));
379 assert!(cell.is_some());
380 assert!(!cell.is_none());
381 assert_eq!(cell.upgrade().unwrap().value, 42);
382 assert_eq!(drops.load(Ordering::Relaxed), 0);
383
384 {
385 let guard = cell.lock();
386 assert!(guard.is_some());
387 assert!(!guard.is_none());
388 assert_eq!(guard.upgrade().unwrap().value, 42);
389 guard.update(Some(DropCounter::new(99, drops.clone())));
390 }
391 assert_eq!(cell.upgrade().unwrap().value, 99);
392 assert_eq!(drops.load(Ordering::Relaxed), 1);
393
394 cell.lock().update(None);
395 assert!(cell.is_none());
396 assert_eq!(drops.load(Ordering::Relaxed), 2);
397
398 rcu_run_callbacks();
399 }
400
401 #[::fuchsia::test]
402 fn test_rcu_lock_array() {
403 let array: RcuLock<RcuArray<u32>> = RcuLock::default();
404 {
405 let scope = RcuReadScope::new();
406 assert!(array.as_slice(&scope).is_empty());
407 assert_eq!(array.get(&scope, 0), None);
408 }
409
410 array.lock().update(vec![10, 20, 30]);
411 {
412 let scope = RcuReadScope::new();
413 assert_eq!(array.as_slice(&scope), &[10, 20, 30]);
414 assert_eq!(array.get(&scope, 1), Some(&20));
415 assert_eq!(array.get(&scope, 3), None);
416 }
417
418 {
419 let guard = array.lock();
420 guard.ensure_at_least(5);
421 let scope = RcuReadScope::new();
422 assert!(guard.as_slice(&scope).len() >= 5);
423 assert_eq!(&guard.as_slice(&scope)[..3], &[10, 20, 30]);
424 assert_eq!(guard.get(&scope, 2), Some(&30));
425 }
426
427 rcu_run_callbacks();
428 }
429
430 #[::fuchsia::test]
431 fn test_rcu_lock_box_and_options() {
432 let boxed: RcuLock<RcuBox<u32>> = RcuLock::new(RcuBox::new(1));
433 assert_eq!(*boxed.read(), 1);
434 assert_eq!(boxed.cloned(), 1);
435 {
436 let guard = boxed.lock();
437 assert_eq!(*guard.read(), 1);
438 assert_eq!(guard.cloned(), 1);
439 guard.update(2);
440 let scope = RcuReadScope::new();
441 assert_eq!(guard.as_ref(&scope), &2);
442 assert_eq!(boxed.as_ref(&scope), &2);
443 }
444
445 let droppable_arc: RcuLock<RcuDroppableArc<u32>> =
446 RcuLock::from(RcuDroppableArc::new(5.into()));
447 assert_eq!(*droppable_arc.read(), 5);
448 assert_eq!(*droppable_arc.to_arc(), 5);
449 {
450 let scope = RcuReadScope::new();
451 assert_eq!(droppable_arc.as_ref(&scope), &5);
452 let guard = droppable_arc.lock();
453 assert_eq!(*guard.read(), 5);
454 assert_eq!(*guard.to_arc(), 5);
455 assert_eq!(guard.as_ref(&scope), &5);
456 let old = guard.update_swap(&scope, Arc::new(6));
457 assert_eq!(*old, 5);
458 assert_eq!(droppable_arc.as_ref(&scope), &6);
459 guard.update(Arc::new(7));
460 assert_eq!(droppable_arc.as_ref(&scope), &7);
461 }
462
463 let option_arc: RcuLock<RcuOptionArc<u32>> = RcuLock::default();
464 assert!(option_arc.read().is_none());
465 {
466 let guard = option_arc.lock();
467 assert!(guard.read().is_none());
468 assert!(guard.to_option_arc().is_none());
469 guard.update(Some(Arc::new(7)));
470 assert_eq!(*guard.to_option_arc().unwrap(), 7);
471 let scope = RcuReadScope::new();
472 assert_eq!(guard.as_ref(&scope), Some(&7));
473 assert_eq!(option_arc.as_ref(&scope), Some(&7));
474 }
475 assert_eq!(*option_arc.to_option_arc().unwrap(), 7);
476
477 let option_box: RcuLock<RcuOptionBox<u32>> = RcuLock::default();
478 assert!(option_box.read().is_none());
479 {
480 let scope = RcuReadScope::new();
481 assert!(option_box.is_none(&scope));
482 assert!(!option_box.is_some(&scope));
483 }
484 {
485 let guard = option_box.lock();
486 let scope = RcuReadScope::new();
487 assert!(guard.read().is_none());
488 assert!(guard.is_none(&scope));
489 assert!(!guard.is_some(&scope));
490 guard.update(Some(8));
491 assert_eq!(guard.cloned(), Some(8));
492 assert!(guard.is_some(&scope));
493 assert!(!guard.is_none(&scope));
494 assert_eq!(guard.as_ref(&scope), Some(&8));
495 }
496 assert_eq!(option_box.cloned(), Some(8));
497 {
498 let scope = RcuReadScope::new();
499 assert!(option_box.is_some(&scope));
500 assert!(!option_box.is_none(&scope));
501 assert_eq!(option_box.as_ref(&scope), Some(&8));
502 }
503
504 let target = Arc::new(11u32);
505 let weak_target = Arc::downgrade(&target);
506 let rcu_weak: RcuLock<RcuWeak<u32>> = RcuLock::default();
507 assert!(rcu_weak.upgrade().is_none());
508 {
509 let guard = rcu_weak.lock();
510 assert!(guard.upgrade().is_none());
511 guard.update(weak_target.clone());
512 assert_eq!(*guard.upgrade().unwrap(), 11);
513 assert!(guard.ptr_eq(&weak_target));
514 assert!(guard.to_weak().upgrade().is_some());
515 let scope = RcuReadScope::new();
516 assert_eq!(guard.strong_count(&scope), 1);
517 }
518 assert_eq!(*rcu_weak.upgrade().unwrap(), 11);
519 assert!(rcu_weak.ptr_eq(&weak_target));
520 assert!(rcu_weak.to_weak().upgrade().is_some());
521 {
522 let scope = RcuReadScope::new();
523 assert_eq!(rcu_weak.strong_count(&scope), 1);
524 }
525
526 rcu_run_callbacks();
527 }
528
529 #[::fuchsia::test]
530 fn test_rcu_lock_conversions_and_accessors() {
531 let cell: RcuLock<RcuBox<u32>, LevelA> = RcuBox::new(20).into();
532 assert_eq!(cell.cloned(), 20);
533
534 assert!(!format!("{cell:?}").is_empty());
535 {
536 let guard = cell.lock();
537 assert!(!format!("{guard:?}").is_empty());
538 }
539
540 unsafe {
542 cell.reset_dependencies();
543 }
544 rcu_run_callbacks();
545 }
546
547 #[::fuchsia::test]
548 fn test_rcu_lock_try_lock_and_ordered_lock() {
549 let cell1: RcuLock<RcuArc<u32>, LevelA> = RcuLock::default();
550 let cell2: RcuLock<RcuArc<u32>, LevelA> = RcuLock::default();
551
552 let guard = cell1.try_lock().expect("try_lock should succeed when unlocked");
553 std::thread::scope(|scope| {
554 scope.spawn(|| {
555 assert!(cell1.try_lock().is_none());
556 });
557 });
558 drop(guard);
559
560 let (guard1, guard2) = ordered_lock(&cell1, &cell2);
561 guard1.update(Some(Arc::new(1)));
562 guard2.update(Some(Arc::new(2)));
563 drop((guard1, guard2));
564
565 let (guard2, guard1) = ordered_lock(&cell2, &cell1);
566 guard1.update(Some(Arc::new(3)));
567 guard2.update(Some(Arc::new(4)));
568 drop((guard2, guard1));
569
570 let guards = ordered_lock_vec(&[&cell2, &cell1]);
571 guards[0].update(Some(Arc::new(20)));
572 guards[1].update(Some(Arc::new(10)));
573 drop(guards);
574
575 assert_eq!(*cell1.upgrade().unwrap(), 10);
576 assert_eq!(*cell2.upgrade().unwrap(), 20);
577 rcu_run_callbacks();
578 }
579
580 #[::fuchsia::test]
581 fn test_rcu_lock_while_holding_outer_lock() {
582 let outer: LockDepMutex<u32, LevelA> = LockDepMutex::new(1);
583 let inner_rcu: RcuLock<RcuArray<u32>> = RcuLock::default();
584
585 let _outer_guard = outer.lock();
586 inner_rcu.lock().update(vec![1, 2, 3]);
587
588 let scope = RcuReadScope::new();
589 assert_eq!(inner_rcu.as_slice(&scope), &[1, 2, 3]);
590 drop(scope);
591 drop(_outer_guard);
592 rcu_run_callbacks();
593 }
594
595 fn assert_rcu_droppable<T: RcuDroppable>() {}
596
597 #[::fuchsia::test]
598 fn test_rcu_lock_droppable() {
599 assert_rcu_droppable::<DynamicRcuLock<RcuArray<u32>>>();
600 assert_rcu_droppable::<RcuLock<RcuArray<u32>>>();
601 assert_rcu_droppable::<RcuLock<RcuBox<u32>, LevelA>>();
602 assert_rcu_droppable::<RcuLock<RcuDroppableArc<u32>, LevelA>>();
603 assert_rcu_droppable::<RcuLock<RcuOptionArc<u32>, LevelA>>();
604 assert_rcu_droppable::<RcuLock<RcuOptionBox<u32>, LevelA>>();
605 }
606
607 #[::fuchsia::test]
608 fn test_dynamic_rcu_lock() {
609 let dyn_cell = DynamicRcuLock::new::<LevelA>(RcuArc::new(Some(Arc::new(10u32))));
610 assert!(dyn_cell.is_some());
611 assert_eq!(*dyn_cell.upgrade().unwrap(), 10);
612
613 assert!(dyn_cell.try_lock().is_some());
614 dyn_cell.lock().update(Some(Arc::new(30)));
615 assert_eq!(*dyn_cell.upgrade().unwrap(), 30);
616
617 let typed_cell: RcuLock<RcuArc<u32>, LevelA> = RcuLock::new(RcuArc::default());
618 let dyn_ref: &DynamicRcuLock<RcuArc<u32>> = &typed_cell;
619 let (g1, g2) = ordered_lock(&dyn_cell, dyn_ref);
620 g1.update(Some(Arc::new(40)));
621 g2.update(Some(Arc::new(50)));
622 drop((g1, g2));
623
624 assert_eq!(*dyn_cell.upgrade().unwrap(), 40);
625 assert_eq!(*typed_cell.upgrade().unwrap(), 50);
626 assert!(!format!("{dyn_cell:?}").is_empty());
627
628 unsafe {
630 dyn_cell.reset_dependencies();
631 }
632 rcu_run_callbacks();
633 }
634
635 #[cfg(feature = "detect_lock_dep_cycles")]
636 #[test]
637 #[should_panic(expected = "Invalid lock ordering cycle detected")]
638 fn test_dynamic_rcu_lock_ordering_cycle_panics() {
639 let dyn_a = DynamicRcuLock::new::<LevelA>(RcuArc::<u32>::default());
640 let dyn_b = DynamicRcuLock::new::<LevelB>(RcuArc::<u32>::default());
641
642 let _guard_b = dyn_b.lock();
643 let _guard_a = dyn_a.lock();
644 }
645
646 #[cfg(feature = "detect_lock_dep_cycles")]
647 #[test]
648 #[should_panic(expected = "Invalid lock ordering cycle detected")]
649 fn test_rcu_lock_ordering_cycle_panics() {
650 let rcu_a: RcuLock<RcuArc<u32>, LevelA> = RcuLock::default();
651 let mutex_b: LockDepMutex<u32, LevelB> = LockDepMutex::new(0);
652
653 let _guard_b = mutex_b.lock();
654 let _guard_a = rcu_a.lock();
655 }
656
657 #[cfg(feature = "detect_lock_dep_cycles")]
658 #[test]
659 #[should_panic(expected = "LockDep: Self-deadlock detected")]
660 fn test_rcu_lock_self_deadlock_panics() {
661 let rcu_a: RcuLock<RcuArc<u32>, LevelA> = RcuLock::default();
662
663 let _guard1 = rcu_a.lock();
664 let _guard2 = rcu_a.lock();
665 }
666
667 #[cfg(feature = "detect_lock_dep_cycles")]
668 #[test]
669 #[should_panic(expected = "Invalid lock ordering cycle detected")]
670 fn test_rcu_lock_try_lock_ordering_cycle_panics() {
671 let rcu_a: RcuLock<RcuArc<u32>, LevelA> = RcuLock::default();
672 let mutex_b: LockDepMutex<u32, LevelB> = LockDepMutex::new(0);
673
674 let _guard_b = mutex_b.try_lock();
675 let _guard_a = rcu_a.try_lock();
676 }
677}