diff options
author | Aapo Alasuutari <aapo.alasuutari@gmail.com> | 2022-10-15 16:49:46 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-15 19:19:46 +0530 |
commit | 75acec0aea3eb39afe9240d7952cc6106363c8de (patch) | |
tree | 09850aa0adb92261de65fe0a6fdefbb58a7e825f /ext/ffi/00_ffi.js | |
parent | 8283d37c51a8fd5f92ba3f8be0bb26f241f864b6 (diff) |
fix(ext/ffi): Fix UnsafeCallback ref'ing making Deno enter a live-loop (#16216)
Fixes #15136
Currently `UnsafeCallback` class' `ref()` and `unref()` methods rely on
the `event_loop_middleware` implementation in core. If even a single
`UnsafeCallback` is ref'ed, then the FFI event loop middleware will
always return `true` to signify that there may still be more work for
the event loop to do.
The middleware handling in core does not wait a moment to check again,
but will instead synchronously directly re-poll the event loop and
middlewares for more work. This becomes a live-loop.
This PR introduces a `Future` implementation for the `CallbackInfo`
struct that acts as the intermediary data storage between an
`UnsafeCallback` and the `libffi` C callback. Ref'ing a callback now
means calling an async op that binds to the `CallbackInfo` Future and
only resolves once the callback is unref'ed. The `libffi` C callback
will call the waker of this Future when it fires to make sure that the
main thread wakes up to receive the callback.
Diffstat (limited to 'ext/ffi/00_ffi.js')
-rw-r--r-- | ext/ffi/00_ffi.js | 16 |
1 files changed, 10 insertions, 6 deletions
diff --git a/ext/ffi/00_ffi.js b/ext/ffi/00_ffi.js index 30a02a609..3f5c57a9c 100644 --- a/ext/ffi/00_ffi.js +++ b/ext/ffi/00_ffi.js @@ -184,6 +184,8 @@ class UnsafeCallback { #refcount; + // Internal promise only meant to keep Deno from exiting + #refpromise; #rid; definition; callback; @@ -208,23 +210,25 @@ ref() { if (this.#refcount++ === 0) { - ops.op_ffi_unsafe_callback_ref(true); + this.#refpromise = core.opAsync( + "op_ffi_unsafe_callback_ref", + this.#rid, + ); } + return this.#refcount; } unref() { // Only decrement refcount if it is positive, and only // unref the callback if refcount reaches zero. if (this.#refcount > 0 && --this.#refcount === 0) { - ops.op_ffi_unsafe_callback_ref(false); + ops.op_ffi_unsafe_callback_unref(this.#rid); } + return this.#refcount; } close() { - if (this.#refcount) { - this.#refcount = 0; - ops.op_ffi_unsafe_callback_ref(false); - } + this.#refcount = 0; core.close(this.#rid); } } |