Repository: tokio-rs/tokio
File: tokio/src/runtime/task/harness.rs (Rust)

Code before:
                // `JoinHandle` before.
                self.core().drop_future_or_output();
            } else if snapshot.is_join_waker_set() {
                // Notify the waker. Reading the waker field is safe per rule 4
                // in task/mod.rs, since the JOIN_WAKER bit is set and the call
                // to transition_to_complete() above set the COMPLETE bit.
                self.trailer().wake_join();

                // If JOIN_INTEREST is still set at this point the `JoinHandle`
                // was not dropped since setting COMPLETE so we unset JOIN_WAKER
                // to give the responsibility of dropping the join waker back to
                // the `JoinHandle`. `JoinHandle` is able to drop the waker when
                // itself gets dropped.
                if self.state().unset_waker_if_join_interested().is_err() {
                    // Unsetting JOIN_WAKER flag will fail if JOIN_INTERESTED is
                    // not set to indicate that the runtime has the responsibility
                    // to drop the join waker here as per rule 7 in task/mod.rs.
                    // Safety:
                    // If JOIN_INTEREST got unset since setting COMPLETE we are
                    // the only ones to have access to the join waker and need
                    // to drop it here because the `JoinHandle` of the task
                    // already got dropped.
                    unsafe {
                        self.trailer().set_waker(None);
                    }
                }
            }
        }));

        // We catch panics here in case invoking a hook panics.
        //
        // We call this in a separate block so that it runs after the task appears to have
        // completed and will still run if the destructor panics.
        if let Some(f) = self.trailer().hooks.task_terminate_callback.as_ref() {
            let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| {
                f(&TaskMeta {
                    id: self.core().task_id,
                    _phantom: Default::default(),
                })
            }));
        }

        // The task has completed execution and will no longer be scheduled.
        let num_release = self.release();

        if self.state().transition_to_terminal(num_release) {
            self.dealloc();
        }
    }

    /// Releases the task from the scheduler. Returns the number of ref-counts

Review comment (bug):
```suggestion
                // Inform the `JoinHandle` that we are done waking the waker by
		// unsetting the `JOIN_WAKER` bit. If the `JoinHandle` has
		// already been dropped, then this fails and we must drop the
		// waker ourselves.
                if self.state().unset_waker_if_join_interested().is_err() {
                    // SAFETY: We have COMPLETE=1 and JOIN_INTEREST=0, so
                    // we have exclusive access to the waker.
                    unsafe { self.trailer().set_waker(None) };
                }
```

Code after:
            } else if snapshot.is_join_waker_set() {
                // Notify the waker. Reading the waker field is safe per rule 4
                // in task/mod.rs, since the JOIN_WAKER bit is set and the call
                // to transition_to_complete() above set the COMPLETE bit.
                self.trailer().wake_join();

                // Inform the `JoinHandle` that we are done waking the waker by
                // unsetting the `JOIN_WAKER` bit. If the `JoinHandle` has
                // already been dropped and `JOIN_INTEREST` is unset, then we must
                // drop the waker ourselves.
                if !self
                    .state()
                    .unset_waker_after_complete()
                    .is_join_interested()
                {
                    // SAFETY: We have COMPLETE=1 and JOIN_INTEREST=0, so
                    // we have exclusive access to the waker.
                    unsafe { self.trailer().set_waker(None) };
                }
            }
        }));

        // We catch panics here in case invoking a hook panics.
        //
        // We call this in a separate block so that it runs after the task appears to have
        // completed and will still run if the destructor panics.
        if let Some(f) = self.trailer().hooks.task_terminate_callback.as_ref() {
            let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| {
                f(&TaskMeta {
                    id: self.core().task_id,
                    _phantom: Default::default(),
                })
            }));
        }

        // The task has completed execution and will no longer be scheduled.
        let num_release = self.release();

        if self.state().transition_to_terminal(num_release) {
            self.dealloc();
        }
    }

    /// Releases the task from the scheduler. Returns the number of ref-counts
    /// that should be decremented.
    fn release(&self) -> usize {
        // We don't actually increment the ref-count here, but the new task is
        // never destroyed, so that's ok.
        let me = ManuallyDrop::new(self.get_new_task());

        if let Some(task) = self.core().scheduler.release(&me) {