summaryrefslogtreecommitdiff
path: root/ext/ffi/00_ffi.js
diff options
context:
space:
mode:
authorAapo Alasuutari <aapo.alasuutari@gmail.com>2022-10-15 16:49:46 +0300
committerGitHub <noreply@github.com>2022-10-15 19:19:46 +0530
commit75acec0aea3eb39afe9240d7952cc6106363c8de (patch)
tree09850aa0adb92261de65fe0a6fdefbb58a7e825f /ext/ffi/00_ffi.js
parent8283d37c51a8fd5f92ba3f8be0bb26f241f864b6 (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.js16
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);
}
}