From 664119841a92d13a297e88032f9985fe7e35f77c Mon Sep 17 00:00:00 2001 From: dave caruso Date: Mon, 21 Aug 2023 16:26:07 -0700 Subject: Implement `napi_ref_threadsafe_function` (#4156) * Implement napi_ref_threadsafe_function * work on this * i hate event loops * little better * clean --- src/bun.js/base.zig | 8 ++++++++ src/bun.js/bindings/napi.cpp | 13 ++++++++++++- src/napi/napi.zig | 7 ++++--- 3 files changed, 24 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig index b08b82c40..e72e196a3 100644 --- a/src/bun.js/base.zig +++ b/src/bun.js/base.zig @@ -1682,6 +1682,14 @@ pub const PollRef = struct { this.status = .active; vm.uws_event_loop.?.refConcurrently(); } + + pub fn refConcurrentlyFromEventLoop(this: *PollRef, loop: *JSC.EventLoop) void { + this.refConcurrently(loop.virtual_machine); + } + + pub fn unrefConcurrentlyFromEventLoop(this: *PollRef, loop: *JSC.EventLoop) void { + this.unrefConcurrently(loop.virtual_machine); + } }; const KQueueGenerationNumber = if (Environment.isMac and Environment.allow_assert) usize else u0; diff --git a/src/bun.js/bindings/napi.cpp b/src/bun.js/bindings/napi.cpp index 8a77723e2..2562242a8 100644 --- a/src/bun.js/bindings/napi.cpp +++ b/src/bun.js/bindings/napi.cpp @@ -46,6 +46,8 @@ #include "JavaScriptCore/JSSourceCode.h" #include "JavaScriptCore/JSNativeStdFunction.h" #include "JavaScriptCore/BigIntObject.h" +#include "ScriptExecutionContext.h" +#include "Strong.h" #include "../modules/ObjectModule.h" @@ -1763,7 +1765,16 @@ extern "C" napi_status napi_create_external(napi_env env, void* data, auto* structure = Bun::NapiExternal::createStructure(vm, globalObject, globalObject->objectPrototype()); JSValue value = JSValue(Bun::NapiExternal::create(vm, structure, data, finalize_hint, finalize_cb)); - JSC::EnsureStillAliveScope ensureStillAlive(value); + + // With `fsevents`, their napi_create_external seems to get immediatly garbage + // collected for some unknown reason. + // See https://github.com/oven-sh/bun/issues/3978 and `fsevents.test.ts` + JSC::Strong* strong = new JSC::Strong(vm, value); + globalObject->scriptExecutionContext()->postTask([strong](auto& context) -> void { + strong->clear(); + delete strong; + }); + *result = toNapi(value); return napi_ok; } diff --git a/src/napi/napi.zig b/src/napi/napi.zig index 99a49bb96..1d3e3e811 100644 --- a/src/napi/napi.zig +++ b/src/napi/napi.zig @@ -1210,7 +1210,7 @@ pub const ThreadSafeFunction = struct { /// Neither does napi_unref_threadsafe_function mark the thread-safe /// functions as able to be destroyed nor does napi_ref_threadsafe_function /// prevent it from being destroyed. - ref_for_process_exit: bool = false, + poll_ref: JSC.PollRef, owning_threads: std.AutoArrayHashMapUnmanaged(u64, void) = .{}, owning_thread_lock: Lock = Lock.init(), @@ -1345,11 +1345,11 @@ pub const ThreadSafeFunction = struct { } pub fn ref(this: *ThreadSafeFunction) void { - this.ref_for_process_exit = true; + this.poll_ref.refConcurrentlyFromEventLoop(this.event_loop); } pub fn unref(this: *ThreadSafeFunction) void { - this.ref_for_process_exit = false; + this.poll_ref.unrefConcurrentlyFromEventLoop(this.event_loop); } pub fn acquire(this: *ThreadSafeFunction) !void { @@ -1415,6 +1415,7 @@ pub export fn napi_create_threadsafe_function( .ctx = context, .channel = ThreadSafeFunction.Queue.init(max_queue_size, bun.default_allocator), .owning_threads = .{}, + .poll_ref = JSC.PollRef.init(), }; function.owning_threads.ensureTotalCapacity(bun.default_allocator, initial_thread_count) catch return genericFailure(); function.finalizer = .{ .ctx = thread_finalize_data, .fun = thread_finalize_cb }; -- cgit v1.2.3