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}