@@ -284,21 +284,34 @@ where
284
284
}
285
285
286
286
pub ( super ) fn drop_join_handle_slow ( self ) {
287
- // Try to unset `JOIN_INTEREST`. This must be done as a first step in
287
+ // Try to unset `JOIN_INTEREST` and `JOIN_WAKER` . This must be done as a first step in
288
288
// case the task concurrently completed.
289
- if self . state ( ) . unset_join_interested ( ) . is_err ( ) {
290
- // It is our responsibility to drop the output. This is critical as
291
- // the task output may not be `Send` and as such must remain with
292
- // the scheduler or `JoinHandle`. i.e. if the output remains in the
293
- // task structure until the task is deallocated, it may be dropped
294
- // by a Waker on any arbitrary thread.
295
- //
296
- // Panics are delivered to the user via the `JoinHandle`. Given that
297
- // they are dropping the `JoinHandle`, we assume they are not
298
- // interested in the panic and swallow it.
299
- let _ = panic:: catch_unwind ( panic:: AssertUnwindSafe ( || {
300
- self . core ( ) . drop_future_or_output ( ) ;
301
- } ) ) ;
289
+ let snapshot = match self . state ( ) . unset_join_interested_and_waker ( ) {
290
+ Ok ( snapshot) => snapshot,
291
+ Err ( snapshot) => {
292
+ // It is our responsibility to drop the output. This is critical as
293
+ // the task output may not be `Send` and as such must remain with
294
+ // the scheduler or `JoinHandle`. i.e. if the output remains in the
295
+ // task structure until the task is deallocated, it may be dropped
296
+ // by a Waker on any arbitrary thread.
297
+ //
298
+ // Panics are delivered to the user via the `JoinHandle`. Given that
299
+ // they are dropping the `JoinHandle`, we assume they are not
300
+ // interested in the panic and swallow it.
301
+ let _ = panic:: catch_unwind ( panic:: AssertUnwindSafe ( || {
302
+ self . core ( ) . drop_future_or_output ( ) ;
303
+ } ) ) ;
304
+ snapshot
305
+ }
306
+ } ;
307
+
308
+ if !snapshot. is_join_waker_set ( ) {
309
+ // If the JOIN_WAKER bit is not set the join handle has exclusive access to the waker
310
+ // at this point following rule 2 in task/mod.rs so we drop the waker at this point
311
+ // together with the join handle.
312
+ unsafe {
313
+ self . trailer ( ) . set_waker ( None ) ;
314
+ }
302
315
}
303
316
304
317
// Drop the `JoinHandle` reference, possibly deallocating the task
@@ -311,7 +324,6 @@ where
311
324
fn complete ( self ) {
312
325
// The future has completed and its output has been written to the task
313
326
// stage. We transition from running to complete.
314
-
315
327
let snapshot = self . state ( ) . transition_to_complete ( ) ;
316
328
317
329
// We catch panics here in case dropping the future or waking the
@@ -343,6 +355,15 @@ where
343
355
} ) ) ;
344
356
}
345
357
358
+ if snapshot. is_join_interested ( ) && snapshot. is_join_waker_set ( ) {
359
+ // If JOIN_INTEREST and JOIN_WAKER are still set at this point, the runtime should
360
+ // drop the join waker as the join handle is not allowed to modify the waker
361
+ // following rule 6 in task/mod.rs
362
+ unsafe {
363
+ self . trailer ( ) . set_waker ( None ) ;
364
+ }
365
+ }
366
+
346
367
// The task has completed execution and will no longer be scheduled.
347
368
let num_release = self . release ( ) ;
348
369
0 commit comments