1
//! Deferred drop handling.
2
//!
3
//! We sometimes have `Arc<dyn Participant>`s we have obtained but don't want to drop yet
4
//!
5
//! See the top-level docs for context.
6
//!
7
//! When we drop the `Arc`, the refcount might become zero.
8
//! Then the inner type would be dropped.
9
//! The inner type is allowed to call back into us (for example, it may drop an `Account`).
10
//! We must therefore not drop a caller's `Participant` with our own state lock held.
11
//!
12
//! This module has a helper type for assuring that we do defer drops.
13
//
14
// There are no separate tests for this module.  Drop bombs are hard to test for,
15
// and the rest of the code is just wrappers.
16

            
17
use super::*;
18

            
19
/// `MutexGuard<State>` but also a list of `Arc<dyn Participant>` to drop when we unlock
20
#[derive(Debug, Default)]
21
pub(super) struct GuardWithDeferredDrop<'m> {
22
    /// The mutex guard
23
    ///
24
    /// Always `Some`; just an `Option` so we can move out during drop
25
    guard: Option<MutexGuard<'m, State>>,
26

            
27
    /// The participants we've acquired and which we want to drop later
28
    deferred_drop: DeferredDrop,
29
}
30

            
31
/// Participants we've acquired and which we want to drop later, convenience alias
32
pub(super) type DeferredDrop = Vec<drop_reentrancy::ProtectedArc<dyn IsParticipant>>;
33

            
34
impl<'m> GuardWithDeferredDrop<'m> {
35
    /// Prepare for handling deferred drops
36
72
    pub(super) fn new(guard: MutexGuard<'m, State>) -> Self {
37
72
        GuardWithDeferredDrop {
38
72
            guard: Some(guard),
39
72
            deferred_drop: vec![],
40
72
        }
41
72
    }
42

            
43
    /// Obtain mutable borrows of the two components
44
104
    pub(super) fn deref_mut_both(&mut self) -> (&mut State, &mut DeferredDrop) {
45
104
        (
46
104
            self.guard.as_mut().expect("deref_mut after drop"),
47
104
            &mut self.deferred_drop,
48
104
        )
49
104
    }
50
}
51

            
52
impl Deref for GuardWithDeferredDrop<'_> {
53
    type Target = State;
54
    fn deref(&self) -> &State {
55
        self.guard.as_ref().expect("deref after drop")
56
    }
57
}
58
impl DerefMut for GuardWithDeferredDrop<'_> {
59
32
    fn deref_mut(&mut self) -> &mut State {
60
32
        self.deref_mut_both().0
61
32
    }
62
}
63

            
64
// We use ProtectedArc.  In tests, that has a drop bomb which requires us to
65
// call `.promise_dropping_is_ok()`, on pain of panicking.  So we must do that here.
66
//
67
// Outside tests, the normal drop order would be precisely correct:
68
// the guard field comes first, so the compiler would drop it before the Arcs.
69
// So we could make this `#[cfg(test)]` (and add some comments above about field order).
70
// However, we prefer to use the same code, so that the correctness of
71
// *production* GuardWithDeferredDrop is assured by the `ProtectedArc`.
72
impl Drop for GuardWithDeferredDrop<'_> {
73
72
    fn drop(&mut self) {
74
72
        let guard = self.guard.take().expect("dropping twice!");
75
72
        drop::<MutexGuard<_>>(guard);
76
        // we just unlocked the guard, so drops that re-enter our code are fine
77
140
        for p in self.deferred_drop.drain(..) {
78
140
            p.promise_dropping_is_ok();
79
140
        }
80
72
    }
81
}