• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! This mod provides the logic for the inner tree structure of the CancellationToken.
2 //!
3 //! CancellationTokens are only light handles with references to TreeNode.
4 //! All the logic is actually implemented in the TreeNode.
5 //!
6 //! A TreeNode is part of the cancellation tree and may have one parent and an arbitrary number of
7 //! children.
8 //!
9 //! A TreeNode can receive the request to perform a cancellation through a CancellationToken.
10 //! This cancellation request will cancel the node and all of its descendants.
11 //!
12 //! As soon as a node cannot get cancelled any more (because it was already cancelled or it has no
13 //! more CancellationTokens pointing to it any more), it gets removed from the tree, to keep the
14 //! tree as small as possible.
15 //!
16 //! # Invariants
17 //!
18 //! Those invariants shall be true at any time.
19 //!
20 //! 1. A node that has no parents and no handles can no longer be cancelled.
21 //!     This is important during both cancellation and refcounting.
22 //!
23 //! 2. If node B *is* or *was* a child of node A, then node B was created *after* node A.
24 //!     This is important for deadlock safety, as it is used for lock order.
25 //!     Node B can only become the child of node A in two ways:
26 //!         - being created with `child_node()`, in which case it is trivially true that
27 //!           node A already existed when node B was created
28 //!         - being moved A->C->B to A->B because node C was removed in `decrease_handle_refcount()`
29 //!           or `cancel()`. In this case the invariant still holds, as B was younger than C, and C
30 //!           was younger than A, therefore B is also younger than A.
31 //!
32 //! 3. If two nodes are both unlocked and node A is the parent of node B, then node B is a child of
33 //!    node A. It is important to always restore that invariant before dropping the lock of a node.
34 //!
35 //! # Deadlock safety
36 //!
37 //! We always lock in the order of creation time. We can prove this through invariant #2.
38 //! Specifically, through invariant #2, we know that we always have to lock a parent
39 //! before its child.
40 //!
41 use crate::loom::sync::{Arc, Mutex, MutexGuard};
42 
43 /// A node of the cancellation tree structure
44 ///
45 /// The actual data it holds is wrapped inside a mutex for synchronization.
46 pub(crate) struct TreeNode {
47     inner: Mutex<Inner>,
48     waker: tokio::sync::Notify,
49 }
50 impl TreeNode {
new() -> Self51     pub(crate) fn new() -> Self {
52         Self {
53             inner: Mutex::new(Inner {
54                 parent: None,
55                 parent_idx: 0,
56                 children: vec![],
57                 is_cancelled: false,
58                 num_handles: 1,
59             }),
60             waker: tokio::sync::Notify::new(),
61         }
62     }
63 
notified(&self) -> tokio::sync::futures::Notified<'_>64     pub(crate) fn notified(&self) -> tokio::sync::futures::Notified<'_> {
65         self.waker.notified()
66     }
67 }
68 
69 /// The data contained inside a TreeNode.
70 ///
71 /// This struct exists so that the data of the node can be wrapped
72 /// in a Mutex.
73 struct Inner {
74     parent: Option<Arc<TreeNode>>,
75     parent_idx: usize,
76     children: Vec<Arc<TreeNode>>,
77     is_cancelled: bool,
78     num_handles: usize,
79 }
80 
81 /// Returns whether or not the node is cancelled
is_cancelled(node: &Arc<TreeNode>) -> bool82 pub(crate) fn is_cancelled(node: &Arc<TreeNode>) -> bool {
83     node.inner.lock().unwrap().is_cancelled
84 }
85 
86 /// Creates a child node
child_node(parent: &Arc<TreeNode>) -> Arc<TreeNode>87 pub(crate) fn child_node(parent: &Arc<TreeNode>) -> Arc<TreeNode> {
88     let mut locked_parent = parent.inner.lock().unwrap();
89 
90     // Do not register as child if we are already cancelled.
91     // Cancelled trees can never be uncancelled and therefore
92     // need no connection to parents or children any more.
93     if locked_parent.is_cancelled {
94         return Arc::new(TreeNode {
95             inner: Mutex::new(Inner {
96                 parent: None,
97                 parent_idx: 0,
98                 children: vec![],
99                 is_cancelled: true,
100                 num_handles: 1,
101             }),
102             waker: tokio::sync::Notify::new(),
103         });
104     }
105 
106     let child = Arc::new(TreeNode {
107         inner: Mutex::new(Inner {
108             parent: Some(parent.clone()),
109             parent_idx: locked_parent.children.len(),
110             children: vec![],
111             is_cancelled: false,
112             num_handles: 1,
113         }),
114         waker: tokio::sync::Notify::new(),
115     });
116 
117     locked_parent.children.push(child.clone());
118 
119     child
120 }
121 
122 /// Disconnects the given parent from all of its children.
123 ///
124 /// Takes a reference to [Inner] to make sure the parent is already locked.
disconnect_children(node: &mut Inner)125 fn disconnect_children(node: &mut Inner) {
126     for child in std::mem::take(&mut node.children) {
127         let mut locked_child = child.inner.lock().unwrap();
128         locked_child.parent_idx = 0;
129         locked_child.parent = None;
130     }
131 }
132 
133 /// Figures out the parent of the node and locks the node and its parent atomically.
134 ///
135 /// The basic principle of preventing deadlocks in the tree is
136 /// that we always lock the parent first, and then the child.
137 /// For more info look at *deadlock safety* and *invariant #2*.
138 ///
139 /// Sadly, it's impossible to figure out the parent of a node without
140 /// locking it. To then achieve locking order consistency, the node
141 /// has to be unlocked before the parent gets locked.
142 /// This leaves a small window where we already assume that we know the parent,
143 /// but neither the parent nor the node is locked. Therefore, the parent could change.
144 ///
145 /// To prevent that this problem leaks into the rest of the code, it is abstracted
146 /// in this function.
147 ///
148 /// The locked child and optionally its locked parent, if a parent exists, get passed
149 /// to the `func` argument via (node, None) or (node, Some(parent)).
with_locked_node_and_parent<F, Ret>(node: &Arc<TreeNode>, func: F) -> Ret where F: FnOnce(MutexGuard<'_, Inner>, Option<MutexGuard<'_, Inner>>) -> Ret,150 fn with_locked_node_and_parent<F, Ret>(node: &Arc<TreeNode>, func: F) -> Ret
151 where
152     F: FnOnce(MutexGuard<'_, Inner>, Option<MutexGuard<'_, Inner>>) -> Ret,
153 {
154     let mut potential_parent = {
155         let locked_node = node.inner.lock().unwrap();
156         match locked_node.parent.clone() {
157             Some(parent) => parent,
158             // If we locked the node and its parent is `None`, we are in a valid state
159             // and can return.
160             None => return func(locked_node, None),
161         }
162     };
163 
164     loop {
165         // Deadlock safety:
166         //
167         // Due to invariant #2, we know that we have to lock the parent first, and then the child.
168         // This is true even if the potential_parent is no longer the current parent or even its
169         // sibling, as the invariant still holds.
170         let locked_parent = potential_parent.inner.lock().unwrap();
171         let locked_node = node.inner.lock().unwrap();
172 
173         let actual_parent = match locked_node.parent.clone() {
174             Some(parent) => parent,
175             // If we locked the node and its parent is `None`, we are in a valid state
176             // and can return.
177             None => {
178                 // Was the wrong parent, so unlock it before calling `func`
179                 drop(locked_parent);
180                 return func(locked_node, None);
181             }
182         };
183 
184         // Loop until we managed to lock both the node and its parent
185         if Arc::ptr_eq(&actual_parent, &potential_parent) {
186             return func(locked_node, Some(locked_parent));
187         }
188 
189         // Drop locked_parent before reassigning to potential_parent,
190         // as potential_parent is borrowed in it
191         drop(locked_node);
192         drop(locked_parent);
193 
194         potential_parent = actual_parent;
195     }
196 }
197 
198 /// Moves all children from `node` to `parent`.
199 ///
200 /// `parent` MUST have been a parent of the node when they both got locked,
201 /// otherwise there is a potential for a deadlock as invariant #2 would be violated.
202 ///
203 /// To acquire the locks for node and parent, use [with_locked_node_and_parent].
move_children_to_parent(node: &mut Inner, parent: &mut Inner)204 fn move_children_to_parent(node: &mut Inner, parent: &mut Inner) {
205     // Pre-allocate in the parent, for performance
206     parent.children.reserve(node.children.len());
207 
208     for child in std::mem::take(&mut node.children) {
209         {
210             let mut child_locked = child.inner.lock().unwrap();
211             child_locked.parent = node.parent.clone();
212             child_locked.parent_idx = parent.children.len();
213         }
214         parent.children.push(child);
215     }
216 }
217 
218 /// Removes a child from the parent.
219 ///
220 /// `parent` MUST be the parent of `node`.
221 /// To acquire the locks for node and parent, use [with_locked_node_and_parent].
remove_child(parent: &mut Inner, mut node: MutexGuard<'_, Inner>)222 fn remove_child(parent: &mut Inner, mut node: MutexGuard<'_, Inner>) {
223     // Query the position from where to remove a node
224     let pos = node.parent_idx;
225     node.parent = None;
226     node.parent_idx = 0;
227 
228     // Unlock node, so that only one child at a time is locked.
229     // Otherwise we would violate the lock order (see 'deadlock safety') as we
230     // don't know the creation order of the child nodes
231     drop(node);
232 
233     // If `node` is the last element in the list, we don't need any swapping
234     if parent.children.len() == pos + 1 {
235         parent.children.pop().unwrap();
236     } else {
237         // If `node` is not the last element in the list, we need to
238         // replace it with the last element
239         let replacement_child = parent.children.pop().unwrap();
240         replacement_child.inner.lock().unwrap().parent_idx = pos;
241         parent.children[pos] = replacement_child;
242     }
243 
244     let len = parent.children.len();
245     if 4 * len <= parent.children.capacity() {
246         // equal to:
247         //    parent.children.shrink_to(2 * len);
248         // but shrink_to was not yet stabilized in our minimal compatible version
249         let old_children = std::mem::replace(&mut parent.children, Vec::with_capacity(2 * len));
250         parent.children.extend(old_children);
251     }
252 }
253 
254 /// Increases the reference count of handles.
increase_handle_refcount(node: &Arc<TreeNode>)255 pub(crate) fn increase_handle_refcount(node: &Arc<TreeNode>) {
256     let mut locked_node = node.inner.lock().unwrap();
257 
258     // Once no handles are left over, the node gets detached from the tree.
259     // There should never be a new handle once all handles are dropped.
260     assert!(locked_node.num_handles > 0);
261 
262     locked_node.num_handles += 1;
263 }
264 
265 /// Decreases the reference count of handles.
266 ///
267 /// Once no handle is left, we can remove the node from the
268 /// tree and connect its parent directly to its children.
decrease_handle_refcount(node: &Arc<TreeNode>)269 pub(crate) fn decrease_handle_refcount(node: &Arc<TreeNode>) {
270     let num_handles = {
271         let mut locked_node = node.inner.lock().unwrap();
272         locked_node.num_handles -= 1;
273         locked_node.num_handles
274     };
275 
276     if num_handles == 0 {
277         with_locked_node_and_parent(node, |mut node, parent| {
278             // Remove the node from the tree
279             match parent {
280                 Some(mut parent) => {
281                     // As we want to remove ourselves from the tree,
282                     // we have to move the children to the parent, so that
283                     // they still receive the cancellation event without us.
284                     // Moving them does not violate invariant #1.
285                     move_children_to_parent(&mut node, &mut parent);
286 
287                     // Remove the node from the parent
288                     remove_child(&mut parent, node);
289                 }
290                 None => {
291                     // Due to invariant #1, we can assume that our
292                     // children can no longer be cancelled through us.
293                     // (as we now have neither a parent nor handles)
294                     // Therefore we can disconnect them.
295                     disconnect_children(&mut node);
296                 }
297             }
298         });
299     }
300 }
301 
302 /// Cancels a node and its children.
cancel(node: &Arc<TreeNode>)303 pub(crate) fn cancel(node: &Arc<TreeNode>) {
304     let mut locked_node = node.inner.lock().unwrap();
305 
306     if locked_node.is_cancelled {
307         return;
308     }
309 
310     // One by one, adopt grandchildren and then cancel and detach the child
311     while let Some(child) = locked_node.children.pop() {
312         // This can't deadlock because the mutex we are already
313         // holding is the parent of child.
314         let mut locked_child = child.inner.lock().unwrap();
315 
316         // Detach the child from node
317         // No need to modify node.children, as the child already got removed with `.pop`
318         locked_child.parent = None;
319         locked_child.parent_idx = 0;
320 
321         // If child is already cancelled, detaching is enough
322         if locked_child.is_cancelled {
323             continue;
324         }
325 
326         // Cancel or adopt grandchildren
327         while let Some(grandchild) = locked_child.children.pop() {
328             // This can't deadlock because the two mutexes we are already
329             // holding is the parent and grandparent of grandchild.
330             let mut locked_grandchild = grandchild.inner.lock().unwrap();
331 
332             // Detach the grandchild
333             locked_grandchild.parent = None;
334             locked_grandchild.parent_idx = 0;
335 
336             // If grandchild is already cancelled, detaching is enough
337             if locked_grandchild.is_cancelled {
338                 continue;
339             }
340 
341             // For performance reasons, only adopt grandchildren that have children.
342             // Otherwise, just cancel them right away, no need for another iteration.
343             if locked_grandchild.children.is_empty() {
344                 // Cancel the grandchild
345                 locked_grandchild.is_cancelled = true;
346                 locked_grandchild.children = Vec::new();
347                 drop(locked_grandchild);
348                 grandchild.waker.notify_waiters();
349             } else {
350                 // Otherwise, adopt grandchild
351                 locked_grandchild.parent = Some(node.clone());
352                 locked_grandchild.parent_idx = locked_node.children.len();
353                 drop(locked_grandchild);
354                 locked_node.children.push(grandchild);
355             }
356         }
357 
358         // Cancel the child
359         locked_child.is_cancelled = true;
360         locked_child.children = Vec::new();
361         drop(locked_child);
362         child.waker.notify_waiters();
363 
364         // Now the child is cancelled and detached and all its children are adopted.
365         // Just continue until all (including adopted) children are cancelled and detached.
366     }
367 
368     // Cancel the node itself.
369     locked_node.is_cancelled = true;
370     locked_node.children = Vec::new();
371     drop(locked_node);
372     node.waker.notify_waiters();
373 }
374