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
400
//! One-shot completion cell: one result, one waiter, one hand-off.
//!
//! `ResultCell` carries a producer's single output to a single consumer and
//! wakes the parked waiter across that hand-off. It is the completion path
//! shared by `moirai-core`'s blocking `TaskResultSlot` and `moirai-async`'s
//! `AsyncResultSlot`: both need this atomic hand-off, and neither may reintroduce
//! a lock or a per-task waker map on the result path.
//!
//! # Roles
//!
//! The cell is reached through an `Arc` shared by exactly two owners:
//!
//! - the **producer** calls [`complete`](ResultCell::complete) exactly once — the tail
//! of a spawned unit of work;
//! - the **consumer** calls [`try_take_ready`](ResultCell::try_take_ready) and
//! [`register`](ResultCell::register) from its own poll or park loop.
//!
//! Because those are the only two owners, the `result` and `waiter` cells need
//! no lock. The type does not enforce that, so [`register`](ResultCell::register)
//! is `unsafe` and its caller vouches for the single consumer. The producer runs
//! once; the consumer is serialized with itself (`poll` takes `Pin<&mut Self>`
//! on the async side, and the blocking side registers once per wait); and `Drop`
//! runs only after the last `Arc`, so it has exclusive access and races neither
//! side.
//!
//! # State machine
//!
//! `state: AtomicU8` is the sole synchronization variable; the `result` and
//! `waiter` cells are touched only while a transition grants exclusive access to
//! them (C = consumer, P = producer):
//!
//! ```text
//! PENDING ──C register──▶ WAITING ──C re-register──▶ UPDATING_WAITER ──C──▶ WAITING
//! │ │
//! │ P complete │ P complete
//! ▼ ▼
//! WRITING ────────────────▶ WRITING ──P──▶ READY ──C take──▶ TAKEN
//! ```
//!
//! `WRITING` is the producer's exclusive claim on `result`, and `READY`
//! publishes it; `UPDATING_WAITER` is the consumer's exclusive claim on `waiter`
//! while it swaps a stale one, past which the producer spins. A waiter that is
//! never replaced (see [`Waiter::REPLACE_ON_REPEAT`]) never enters
//! `UPDATING_WAITER`, and monomorphization removes that arm entirely.
//!
//! # Cell-access invariants (what the per-site `// Safety:` comments rely on)
//!
//! 1. **`result`: written once, read once.** Only the producer writes it, only
//! under `WRITING` (entered by winning the producer transition, so no
//! consumer can see it yet). It is read exactly once — by the unique
//! `READY -> TAKEN` consumer transition, or by `Drop` at `READY` when the
//! consumer never took it.
//! 2. **`waiter`: written by the consumer, read once by the producer.** The
//! consumer writes it under `PENDING` (published by the `PENDING -> WAITING`
//! release transition) or under the `UPDATING_WAITER` claim. The producer
//! reads it exactly once, on `WAITING -> WRITING`; otherwise `Drop` at
//! `WAITING` drops it. A *failed* publish transition proves no producer
//! observed the write, so the consumer drops its own value.
//! 3. **No lost wakeup.** [`complete`](ResultCell::complete) on the `PENDING ->
//! WRITING` path (it beat registration) deliberately does not wake: no waiter
//! is registered yet. Liveness therefore requires the consumer to check →
//! [`register`](ResultCell::register) → **re-check**; should `complete` land in that
//! window, the re-check observes `READY`. That re-check is load-bearing, not
//! defensive — dropping it reintroduces a hang.
//!
//! # Ordering
//!
//! Each cell access is ordered by a release/acquire pair on `state`: the writer
//! releases on the publishing transition, the reader acquires on the transition
//! that reads the cell. Thus `PENDING -> WAITING` and the `UPDATING_WAITER ->
//! WAITING` store are `Release` (they publish `waiter`), while `WAITING ->
//! WRITING` and `READY -> TAKEN` are `Acquire` (they read a cell). The `PENDING
//! -> WRITING` success is `Relaxed`: that path reads neither cell before its own
//! `store(READY, Release)` publishes `result`, so it carries no incoming edge to
//! establish.
//!
//! # The waiter payload
//!
//! [`Waiter`] abstracts the parked handle: `thread::Thread` for the blocking
//! side, `Waker` for the async one. The two differ in exactly one behaviour, and
//! it is a trait constant rather than a branch —
//! [`REPLACE_ON_REPEAT`](Waiter::REPLACE_ON_REPEAT) is `false` for a thread,
//! which parks once per wait and must not be overwritten, and `true` for a
//! waker, which a re-poll may legitimately replace. Each instantiation therefore
//! compiles to its own machine, and both share this one copy of the protocol,
//! its invariants and its ordering argument.
//!
//! # Layout
//!
//! The cell is packed by default: the state word sits beside the two cells with
//! no padding, which is what a per-task allocation wants. A caller that wants the
//! state in an interference sector of its own supplies that as the
//! [`StateWord`] — `moirai-core`'s `TaskResultSlot` passes
//! `CacheAligned<AtomicU8>` — and the machine runs identically either way, since
//! the alignment never reaches the protocol.
use UnsafeCell;
use MaybeUninit;
use ;
pub use StateWord;
const RESULT_PENDING: u8 = 0;
const RESULT_WAITING: u8 = 1;
const RESULT_UPDATING_WAITER: u8 = 2;
const RESULT_WRITING: u8 = 3;
const RESULT_READY: u8 = 4;
const RESULT_TAKEN: u8 = 5;
/// A handle that can be parked on and woken once.
///
/// See the [module docs](self#the-waiter-payload) for the one behaviour the two
/// implementations differ in.
/// A thread parks once per wait, so a repeat registration is a no-op.
/// A waker may be replaced between polls, so the newest registration wins.
/// Single-producer, single-consumer completion cell for one unit of work.
///
/// The state word's storage is a parameter ([`StateWord`]), so each caller keeps
/// the layout it needs; see [the layout note](self#layout).
// Safety: the cell has one producer and one consumer. Atomic states serialize
// result publication, result consumption, and waiter updates, so concurrent
// `&self` use is sound exactly when the payload and the waiter may each move
// between threads.
unsafe
// Safety: shared access is mediated by the state machine; the result and waiter
// cells are touched only after the corresponding atomic transition succeeds.
unsafe