@@ -36,8 +36,12 @@ const JOIN_WAKER: usize = 0b10_000;
36
36
/// The task has been forcibly cancelled.
37
37
const CANCELLED : usize = 0b100_000 ;
38
38
39
+ const TERMINAL : usize = 0b1_000_000 ;
40
+
39
41
/// All bits.
40
- const STATE_MASK : usize = LIFECYCLE_MASK | NOTIFIED | JOIN_INTEREST | JOIN_WAKER | CANCELLED ;
42
+ // const STATE_MASK: usize = LIFECYCLE_MASK | NOTIFIED | JOIN_INTEREST | JOIN_WAKER | CANCELLED;
43
+ const STATE_MASK : usize =
44
+ LIFECYCLE_MASK | NOTIFIED | JOIN_INTEREST | JOIN_WAKER | CANCELLED | TERMINAL ;
41
45
42
46
/// Bits used by the ref count portion of the state.
43
47
const REF_COUNT_MASK : usize = !STATE_MASK ;
@@ -89,6 +93,20 @@ pub(crate) enum TransitionToNotifiedByRef {
89
93
Submit ,
90
94
}
91
95
96
+ #[ must_use]
97
+ pub ( crate ) enum TransitionToJoinHandleDrop {
98
+ Failed ,
99
+ OkDoNothing ,
100
+ OkDropJoinWaker ,
101
+ }
102
+
103
+ #[ must_use]
104
+ pub ( crate ) enum TransitionToTerminal {
105
+ OkDoNothing ,
106
+ OkDealloc ,
107
+ FailedDropJoinWaker ,
108
+ }
109
+
92
110
/// All transitions are performed via RMW operations. This establishes an
93
111
/// unambiguous modification order.
94
112
impl State {
@@ -174,30 +192,69 @@ impl State {
174
192
} )
175
193
}
176
194
195
+ pub ( super ) fn transition_to_join_handle_drop ( & self ) -> TransitionToJoinHandleDrop {
196
+ self . fetch_update_action ( |mut snapshot| {
197
+ if snapshot. is_join_interested ( ) {
198
+ snapshot. unset_join_interested ( )
199
+ }
200
+
201
+ if snapshot. is_complete ( ) && !snapshot. is_terminal ( ) {
202
+ ( TransitionToJoinHandleDrop :: Failed , None )
203
+ } else if snapshot. is_join_waker_set ( ) {
204
+ snapshot. unset_join_waker ( ) ;
205
+ ( TransitionToJoinHandleDrop :: OkDropJoinWaker , Some ( snapshot) )
206
+ } else {
207
+ ( TransitionToJoinHandleDrop :: OkDoNothing , Some ( snapshot) )
208
+ }
209
+ } )
210
+ }
211
+
177
212
/// Transitions the task from `Running` -> `Complete`.
178
213
pub ( super ) fn transition_to_complete ( & self ) -> Snapshot {
179
214
const DELTA : usize = RUNNING | COMPLETE ;
180
215
181
216
let prev = Snapshot ( self . val . fetch_xor ( DELTA , AcqRel ) ) ;
182
217
assert ! ( prev. is_running( ) ) ;
183
218
assert ! ( !prev. is_complete( ) ) ;
219
+ assert ! ( !prev. is_terminal( ) ) ;
184
220
185
221
Snapshot ( prev. 0 ^ DELTA )
186
222
}
187
223
188
224
/// Transitions from `Complete` -> `Terminal`, decrementing the reference
189
225
/// count the specified number of times.
190
226
///
191
- /// Returns true if the task should be deallocated.
192
- pub ( super ) fn transition_to_terminal ( & self , count : usize ) -> bool {
193
- let prev = Snapshot ( self . val . fetch_sub ( count * REF_ONE , AcqRel ) ) ;
194
- assert ! (
195
- prev. ref_count( ) >= count,
196
- "current: {}, sub: {}" ,
197
- prev. ref_count( ) ,
198
- count
199
- ) ;
200
- prev. ref_count ( ) == count
227
+ /// Returns `TransitionToTerminal::OkDoNothing` if transition was successful but the task can
228
+ /// not already be deallocated.
229
+ /// Returns `TransitionToTerminal::OkDealloc` if the task should be deallocated.
230
+ /// Returns `TransitionToTerminal::FailedDropJoinWaker` if the transition failed because of a
231
+ /// the join waker being the only last. In this case the reference count will not be decremented
232
+ /// but the `JOIN_WAKER` bit will be unset.
233
+ pub ( super ) fn transition_to_terminal ( & self , count : usize ) -> TransitionToTerminal {
234
+ self . fetch_update_action ( |mut snapshot| {
235
+ assert ! ( !snapshot. is_running( ) ) ;
236
+ assert ! ( snapshot. is_complete( ) ) ;
237
+ assert ! ( !snapshot. is_terminal( ) ) ;
238
+ assert ! (
239
+ snapshot. ref_count( ) >= count,
240
+ "current: {}, sub: {}" ,
241
+ snapshot. ref_count( ) ,
242
+ count
243
+ ) ;
244
+
245
+ if snapshot. ref_count ( ) == count {
246
+ snapshot. 0 -= count * REF_ONE ;
247
+ snapshot. 0 |= TERMINAL ;
248
+ ( TransitionToTerminal :: OkDealloc , Some ( snapshot) )
249
+ } else if !snapshot. is_join_interested ( ) && snapshot. is_join_waker_set ( ) {
250
+ snapshot. unset_join_waker ( ) ;
251
+ ( TransitionToTerminal :: FailedDropJoinWaker , Some ( snapshot) )
252
+ } else {
253
+ snapshot. 0 -= count * REF_ONE ;
254
+ snapshot. 0 |= TERMINAL ;
255
+ ( TransitionToTerminal :: OkDoNothing , Some ( snapshot) )
256
+ }
257
+ } )
201
258
}
202
259
203
260
/// Transitions the state to `NOTIFIED`.
@@ -371,25 +428,6 @@ impl State {
371
428
. map_err ( |_| ( ) )
372
429
}
373
430
374
- /// Tries to unset the `JOIN_INTEREST` flag.
375
- ///
376
- /// Returns `Ok` if the operation happens before the task transitions to a
377
- /// completed state, `Err` otherwise.
378
- pub ( super ) fn unset_join_interested ( & self ) -> UpdateResult {
379
- self . fetch_update ( |curr| {
380
- assert ! ( curr. is_join_interested( ) ) ;
381
-
382
- if curr. is_complete ( ) {
383
- return None ;
384
- }
385
-
386
- let mut next = curr;
387
- next. unset_join_interested ( ) ;
388
-
389
- Some ( next)
390
- } )
391
- }
392
-
393
431
/// Sets the `JOIN_WAKER` bit.
394
432
///
395
433
/// Returns `Ok` if the bit is set, `Err` otherwise. This operation fails if
@@ -557,6 +595,10 @@ impl Snapshot {
557
595
self . 0 & COMPLETE == COMPLETE
558
596
}
559
597
598
+ pub ( super ) fn is_terminal ( self ) -> bool {
599
+ self . 0 & TERMINAL == TERMINAL
600
+ }
601
+
560
602
pub ( super ) fn is_join_interested ( self ) -> bool {
561
603
self . 0 & JOIN_INTEREST == JOIN_INTEREST
562
604
}
0 commit comments