@@ -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,70 @@ 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 ( ) || !snapshot. is_join_waker_set ( ) )
202
+ {
203
+ ( TransitionToJoinHandleDrop :: Failed , None )
204
+ } else if snapshot. is_join_waker_set ( ) {
205
+ snapshot. unset_join_waker ( ) ;
206
+ ( TransitionToJoinHandleDrop :: OkDropJoinWaker , Some ( snapshot) )
207
+ } else {
208
+ ( TransitionToJoinHandleDrop :: OkDoNothing , Some ( snapshot) )
209
+ }
210
+ } )
211
+ }
212
+
177
213
/// Transitions the task from `Running` -> `Complete`.
178
214
pub ( super ) fn transition_to_complete ( & self ) -> Snapshot {
179
215
const DELTA : usize = RUNNING | COMPLETE ;
180
216
181
217
let prev = Snapshot ( self . val . fetch_xor ( DELTA , AcqRel ) ) ;
182
218
assert ! ( prev. is_running( ) ) ;
183
219
assert ! ( !prev. is_complete( ) ) ;
220
+ assert ! ( !prev. is_terminal( ) ) ;
184
221
185
222
Snapshot ( prev. 0 ^ DELTA )
186
223
}
187
224
188
225
/// Transitions from `Complete` -> `Terminal`, decrementing the reference
189
226
/// count the specified number of times.
190
227
///
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
228
+ /// Returns `TransitionToTerminal::OkDoNothing` if transition was successful but the task can
229
+ /// not already be deallocated.
230
+ /// Returns `TransitionToTerminal::OkDealloc` if the task should be deallocated.
231
+ /// Returns `TransitionToTerminal::FailedDropJoinWaker` if the transition failed because of a
232
+ /// the join waker being the only last. In this case the reference count will not be decremented
233
+ /// but the `JOIN_WAKER` bit will be unset.
234
+ pub ( super ) fn transition_to_terminal ( & self , count : usize ) -> TransitionToTerminal {
235
+ self . fetch_update_action ( |mut snapshot| {
236
+ assert ! ( !snapshot. is_running( ) ) ;
237
+ assert ! ( snapshot. is_complete( ) ) ;
238
+ assert ! ( !snapshot. is_terminal( ) ) ;
239
+ assert ! (
240
+ snapshot. ref_count( ) >= count,
241
+ "current: {}, sub: {}" ,
242
+ snapshot. ref_count( ) ,
243
+ count
244
+ ) ;
245
+
246
+ if snapshot. ref_count ( ) == count {
247
+ snapshot. 0 -= count * REF_ONE ;
248
+ snapshot. 0 |= TERMINAL ;
249
+ ( TransitionToTerminal :: OkDealloc , Some ( snapshot) )
250
+ } else if !snapshot. is_join_interested ( ) && snapshot. is_join_waker_set ( ) {
251
+ snapshot. unset_join_waker ( ) ;
252
+ ( TransitionToTerminal :: FailedDropJoinWaker , Some ( snapshot) )
253
+ } else {
254
+ snapshot. 0 -= count * REF_ONE ;
255
+ snapshot. 0 |= TERMINAL ;
256
+ ( TransitionToTerminal :: OkDoNothing , Some ( snapshot) )
257
+ }
258
+ } )
201
259
}
202
260
203
261
/// Transitions the state to `NOTIFIED`.
@@ -371,25 +429,6 @@ impl State {
371
429
. map_err ( |_| ( ) )
372
430
}
373
431
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
432
/// Sets the `JOIN_WAKER` bit.
394
433
///
395
434
/// Returns `Ok` if the bit is set, `Err` otherwise. This operation fails if
@@ -557,6 +596,10 @@ impl Snapshot {
557
596
self . 0 & COMPLETE == COMPLETE
558
597
}
559
598
599
+ pub ( super ) fn is_terminal ( self ) -> bool {
600
+ self . 0 & TERMINAL == TERMINAL
601
+ }
602
+
560
603
pub ( super ) fn is_join_interested ( self ) -> bool {
561
604
self . 0 & JOIN_INTEREST == JOIN_INTEREST
562
605
}
0 commit comments