tor_memquota/mtracker/reclaim/
deferred_drop.rs

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
17use super::*;
18
19/// `MutexGuard<State>` but also a list of `Arc<dyn Participant>` to drop when we unlock
20#[derive(Debug, Default)]
21pub(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
32pub(super) type DeferredDrop = Vec<drop_reentrancy::ProtectedArc<dyn IsParticipant>>;
33
34impl<'m> GuardWithDeferredDrop<'m> {
35    /// Prepare for handling deferred drops
36    pub(super) fn new(guard: MutexGuard<'m, State>) -> Self {
37        GuardWithDeferredDrop {
38            guard: Some(guard),
39            deferred_drop: vec![],
40        }
41    }
42
43    /// Obtain mutable borrows of the two components
44    pub(super) fn deref_mut_both(&mut self) -> (&mut State, &mut DeferredDrop) {
45        (
46            self.guard.as_mut().expect("deref_mut after drop"),
47            &mut self.deferred_drop,
48        )
49    }
50}
51
52impl std::ops::Deref for GuardWithDeferredDrop<'_> {
53    type Target = State;
54    fn deref(&self) -> &State {
55        self.guard.as_ref().expect("deref after drop")
56    }
57}
58impl std::ops::DerefMut for GuardWithDeferredDrop<'_> {
59    fn deref_mut(&mut self) -> &mut State {
60        self.deref_mut_both().0
61    }
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`.
72impl Drop for GuardWithDeferredDrop<'_> {
73    fn drop(&mut self) {
74        let guard = self.guard.take().expect("dropping twice!");
75        drop::<MutexGuard<_>>(guard);
76        // we just unlocked the guard, so drops that re-enter our code are fine
77        for p in self.deferred_drop.drain(..) {
78            p.promise_dropping_is_ok();
79        }
80    }
81}