1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
//! A token that signals a cancellation request to one or more tasks, with
//! child tokens that follow their parent.
//!
//! [`CancellationToken::cancel`] marks the token and every token derived
//! from it by [`child_token`](CancellationToken::child_token), and wakes
//! every task waiting in [`cancelled`](CancellationToken::cancelled). A child
//! can be cancelled alone; cancelling a child never cancels its parent. The
//! API is the established async cancellation-token API; nothing here needs a
//! runtime.
//!
//! ```
//! use nuclei::sync::CancellationToken;
//!
//! let parent = CancellationToken::new();
//! let child = parent.child_token();
//! assert!(!child.is_cancelled());
//! parent.cancel();
//! assert!(child.is_cancelled());
//! ```
//!
//! The tree, what `cancel` promises and the progress guarantee of each
//! operation are documented on [`CancellationToken`], where a reader of the
//! public API finds them. This module's docs keep the argument for the
//! memory ordering of the tree.
//!
//! # Memory ordering of the tree
//!
//! `child_token` and `cancel` race: a child added while the parent is being
//! cancelled must end up cancelled. The two sides use the same pattern, a
//! store followed by a `SeqCst` fence followed by a read of the other's store
//! (Dekker):
//!
//! - `child_token` publishes the child in the parent's registry, fences, and
//! then reads the parent's flag.
//! - `cancel` sets the flag (unless an earlier call did), fences, and then
//! iterates the registry.
//!
//! The fences are ordered one way or the other in the single `SeqCst` order.
//! If the child's fence comes first, everything before it (the registry
//! insert) is visible to the reads after the canceller's fence, so the
//! iteration, which starts after that fence, yields the child: the registry
//! guarantees that an entry present from the start of an iteration to its end
//! is yielded exactly once. If the canceller's fence comes first, the flag
//! set before it is visible to the read after the child's fence, so the child
//! sees its parent cancelled and cancels itself. Either way the child is
//! cancelled. The same argument covers the registry itself being created
//! lazily, since its publication is a store before the child's fence.
//!
//! A `cancel` that finds the flag already set stores nothing, but it fences
//! and iterates all the same, and that is what its own guarantee rests on:
//! a child whose `child_token` had completed before the call is in the
//! registry for the whole walk, so the registry yields it. A child inserted
//! while the walk runs is the race above, and one of the two sides covers
//! it: the call that stored the flag, or the child, which reads the flag
//! after its own fence. So a child being created meanwhile is cancelled once
//! both the `cancel` and its own `child_token` have returned.
//!
//! Under `--cfg loom` the registry is a loom `Mutex` around a `BTreeMap` (the
//! map in the real build is a lock-free kovan map that loom cannot
//! instrument; the ordered map keeps the model deterministic), and
//! [`Arc`]/[`Weak`] are the small models in `rc`, since loom has neither a
//! weak reference nor `Arc::into_inner`. So the loom models check the
//! protocol around the registry (the flag, the wakeups, the order of insert,
//! visit and removal, the ownership of nodes) with a registry that is
//! atomic by itself; the argument above is what covers the real registry.
use fmt;
use Future;
use ;
pub use ;
pub use ;
use Node;
use RunUntilCancelled;
use ;
use ;
/// A token which can be used to signal a cancellation request to one or more
/// tasks.
///
/// Tasks call [`cancelled`](Self::cancelled) to get a future that completes
/// when cancellation is requested, and [`cancel`](Self::cancel) requests it.
/// A clone is another handle to the same token: cancelling one cancels all.
/// A [`child_token`](Self::child_token) is cancelled with its parent, and can
/// be cancelled alone.
///
/// # The tree
///
/// A token is an `Arc` of a node. A node holds its own cancelled flag (an
/// [`Event`](crate::sync::Event), which also wakes the waiters), a *strong* handle to
/// its parent node, and, once it has a child, a registry of its children
/// that holds a *weak* handle to each of them.
///
/// - A parent whose tokens are all gone stays alive as long as any child is,
/// as a relay: cancelling a grandparent still reaches the grandchildren. A
/// node nobody can cancel or wait on any more is freed.
/// - Memory is bounded by the live tokens. A node removes itself from its
/// parent's registry when it is freed, so the registry holds only the
/// children that exist.
/// - Freeing a node walks up the chain of ancestors it was the last owner of,
/// in a loop and not by recursion, so a chain of a million nested tokens
/// can be dropped without overflowing the stack.
///
/// # Cancelling
///
/// `cancel` sets the node's flag, which wakes its waiters, and then walks the
/// whole subtree with an explicit stack: it sets the flag of every descendant
/// that is not set yet, and descends into every descendant, those some other
/// call already set included. So:
///
/// - When any `cancel` call returns, the token it was called on and every
/// descendant that existed when the call began (its `child_token` had
/// completed) are cancelled, and their waiters woken, whether this call or
/// another one set the flag first. A call on an already cancelled token
/// still walks its subtree, so it too returns with the subtree cancelled.
/// - A descendant being created at the same moment is cancelled by the time
/// both calls have returned: either the new child sees its parent
/// cancelled and cancels itself, or the walk sees the child.
/// - The price is the walk: every call visits every descendant once, so
/// concurrent or repeated calls over one tree each pay for it. Cancel a
/// large tree once.
/// - Cancellation is not atomic over the tree: while a call runs, another
/// thread can see a child cancelled and then a sibling not yet cancelled.
///
/// # Progress
///
/// - Wait-free: [`is_cancelled`](CancellationToken::is_cancelled) (one load),
/// [`Clone`], dropping a token that is not the last owner of its node,
/// [`cancelled`](CancellationToken::cancelled) and
/// [`cancelled_owned`](CancellationToken::cancelled_owned) themselves
/// (they only build the future), and a poll of the future once the token is
/// cancelled (one load).
/// - Lock-free: [`cancel`](CancellationToken::cancel) and the first poll of a
/// future of an uncancelled token. Setting a flag is a lock-free queue
/// operation, and the visit of the descendants reads each registry with
/// the map's iterator, which restarts a bucket whose walk was disturbed
/// by a concurrent update. A `cancel` never waits for another `cancel`:
/// each walks the subtree on its own. The time it takes grows with the
/// number of descendants, whether or not they were cancelled already.
/// - Neither wait-free nor lock-free:
/// [`child_token`](CancellationToken::child_token) and dropping the last
/// owner of a node. They insert into or remove from the parent's registry
/// (a CAS that retries when another thread changed the same bucket), and
/// the registry is a map that grows past 48 children: a write that meets
/// the resize in progress waits for the thread resizing it.
///
/// Waking a task calls its [`Waker`](std::task::Waker), which is the
/// executor's and is not counted.
///
/// ```
/// use nuclei::sync::CancellationToken;
/// use std::future::Future;
/// use std::pin::pin;
/// use std::task::{Context, Poll, Waker};
///
/// let token = CancellationToken::new();
/// let clone = token.clone();
/// let mut cx = Context::from_waker(Waker::noop());
/// let mut cancelled = pin!(clone.cancelled());
/// assert_eq!(cancelled.as_mut().poll(&mut cx), Poll::Pending);
/// token.cancel();
/// assert_eq!(cancelled.as_mut().poll(&mut cx), Poll::Ready(()));
/// ```