fix(ext/ffi): Fix re-ref'ing UnsafeCallback #17704
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.
Currently,
UnsafeCallback
ref'ing and unref'ing uses aCancelHandle
in theUnsafeCallback
resource. When anUnsafeCallback
gets unref'ed (ref counter goes back to 0), itsCancelHandle
is triggered to resolve the Future / Promise that keeps the event loop alive and provides aWaker
for theCallbackInfo
. If the sameUnsafeCallback
then gets re-ref'ed afterwards the sameCancelHandle
gets reused and it immediately cancels the Future, leading to Deno's event loop not staying alive and worst of all severing theWaker
's tie to the Deno event loop.There issue is that currently, an
UnsafeCallback
that is unref'ed (or never ref'ed in the first place) cannot wake the Deno event loop up as it either doesn't have a Waker, or the Waker is no longer tied to the event loop. So eg. this will not work:The timeout finishes in something like a 300 000 years but the callback will never be resolved: Any call to this callback will send Deno's event loop work to do, but the event loop can never be woken up.
Fix
UnsafeCallback.threadSafe()
static constructor function that creates a callback and refs it once.core.unrefOp
mechanism. ie. The Promise/Future does not get resolved or canceled, it is simply unref'ed.