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//!
41use 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.
46pub(crate) struct TreeNode {
47 inner: Mutex<Inner>,
48 waker: tokio::sync::Notify,
49}
50impl TreeNode {
51 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
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.
73struct 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
82pub(crate) fn is_cancelled(node: &Arc<TreeNode>) -> bool {
83 node.inner.lock().unwrap().is_cancelled
84}
85
86/// Creates a child node
87pub(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.
125fn disconnect_children(node: &mut Inner) {
126 for child: Arc in std::mem::take(&mut node.children) {
127 let mut locked_child: MutexGuard<'_, Inner> = 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)).
150fn with_locked_node_and_parent<F, Ret>(node: &Arc<TreeNode>, func: F) -> Ret
151where
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 aquire the locks for node and parent, use [with_locked_node_and_parent].
204fn move_children_to_parent(node: &mut Inner, parent: &mut Inner) {
205 // Pre-allocate in the parent, for performance
206 parent.children.reserve(additional:node.children.len());
207
208 for child: Arc in std::mem::take(&mut node.children) {
209 {
210 let mut child_locked: MutexGuard<'_, Inner> = 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 aquire the locks for node and parent, use [with_locked_node_and_parent].
222fn 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.
255pub(crate) fn increase_handle_refcount(node: &Arc<TreeNode>) {
256 let mut locked_node: MutexGuard<'_, Inner> = 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.
269pub(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.
303pub(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