Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/js/export_module.zig
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ const class_runtime = @import("class_runtime.zig");
///
/// The DSL internally manages an atomic refcount for module instances across
/// different N-API environments, and uses the same env lifecycle to retain a
/// shared `js.io()` handle for the addon.
/// shared `js.io()` handle for the addon. Modules with lifecycle hooks also
/// serialize initialization and cleanup across environments.
///
/// Usage Examples:
/// ```zig
Expand Down Expand Up @@ -66,6 +67,7 @@ pub fn exportModule(comptime Module: type, comptime options: anytype) void {

const State = struct {
var env_refcount: std.atomic.Value(u32) = std.atomic.Value(u32).init(0);
var lifecycle_mutex: std.Io.Mutex = .init;

// addEnvCleanupHook requires a non-null *Data pointer.
const CleanupData = struct {
Expand All @@ -75,6 +77,10 @@ pub fn exportModule(comptime Module: type, comptime options: anytype) void {

fn cleanupHook(_: *CleanupData) void {
if (has_lifecycle) {
const io = io_context.io();
lifecycle_mutex.lockUncancelable(io);
defer lifecycle_mutex.unlock(io);

const prev = env_refcount.fetchSub(1, .acq_rel);
const new_refcount = prev - 1;
if (has_cleanup) {
Expand All @@ -96,6 +102,12 @@ pub fn exportModule(comptime Module: type, comptime options: anytype) void {
io_context.release();
};

const io = io_context.io();
if (has_lifecycle) {
State.lifecycle_mutex.lockUncancelable(io);
}
defer if (has_lifecycle) State.lifecycle_mutex.unlock(io);

var prev_refcount: u32 = 0;
if (has_lifecycle) {
prev_refcount = State.env_refcount.fetchAdd(1, .monotonic);
Expand Down
Loading