Fix weak references to coroutines #1097
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
root_implements::NonDelegatingReleasesetsm_references = 1prior to initiating destruction so that the destructor sees a nonzero reference count. As a side effect, it also breaks the connection to the weak reference control block.~root_implementsperforms a bonussubtract_referenceto clean up any weak reference control block that may have re-materialized during destruction. The extra decrement is safe because we setm_references = 1earlier.However, if the
root_implements::Releasewas overriden by a derived class, the derived class'sReleasemay not do the samem_references = 1trick, and then the bonus decrement in the destructor will decrement below zero.Who would override
root_implements::Release?promise_base, that's who. As a result, a weak reference to a coroutine turns into poison when the coroutine destructs, because the control block now has a strong reference of 4 billion and a pointer to an already-destroyed object.The logic to set
m_referencesto 1 is now moved intosubtract_referenceso that derived classes don't have to know this One Weird Trick. The actual decrementing happens insubtract_final_reference, which is the version that theroot_implementsdestructor calls, since it knows that the object is finally going away and isn't preparing for destruction.Setting
m_referencesto 1 had been done withmemory_order_cst(default), but I thinkmemory_order_relaxedis sufficient. Since the external reference count is zero, there are no other threads with access to the object (outstanding weak references will not resolve), so there are no data dependencies.Created new tests to validate the "weak reference created during destruction" code path, as well as to validate that weak references to coroutines work. (The
weak,coroutinetest failed prior to the fix.)