Skip to content
Open
Changes from 3 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
129 changes: 99 additions & 30 deletions src/scope.zig
Original file line number Diff line number Diff line change
Expand Up @@ -440,8 +440,99 @@ pub const Scope = struct {
}
};

var global_scope: ?*Scope = null;
var global_scope_mutex = Mutex{};
/// Thread-safe wrapper for global scope access
const GlobalScopeWrapper = struct {
scope: ?*Scope,
allocator: ?Allocator,
mutex: Mutex,
is_alive: bool,

const Self = @This();

pub fn init() Self {
return .{
.scope = null,
.allocator = null,
.mutex = Mutex{},
.is_alive = true,
};
}

/// Get or create the global scope
pub fn getOrCreate(self: *Self, allocator: Allocator) !*Scope {
self.mutex.lock();
defer self.mutex.unlock();

if (!self.is_alive) {
return error.GlobalScopeShutdown;
}

if (self.scope == null) {
const scope = try allocator.create(Scope);
scope.* = Scope.init(allocator);
self.scope = scope;
self.allocator = allocator;
}

return self.scope.?;
}

/// Get the global scope if it exists
pub fn get(self: *Self) ?*Scope {
self.mutex.lock();
defer self.mutex.unlock();

if (!self.is_alive) {
return null;
}

return self.scope;
}

/// Safely deinitialize the global scope
pub fn deinit(self: *Self) void {
self.mutex.lock();
defer self.mutex.unlock();

if (self.scope) |scope| {
scope.deinit();
if (self.allocator) |allocator| {
allocator.destroy(scope);
}
self.scope = null;
}
self.allocator = null;
self.is_alive = false;
}
Comment thread
Litarnus marked this conversation as resolved.

/// Check if the global scope is still alive
pub fn isAlive(self: *Self) bool {
self.mutex.lock();
defer self.mutex.unlock();
return self.is_alive;
}

/// Reset the wrapper to initial state while keeping the same mutex
pub fn reset(self: *Self) void {
self.mutex.lock();
defer self.mutex.unlock();

// Clean up existing scope if any
if (self.scope) |scope| {
scope.deinit();
if (self.allocator) |allocator| {
allocator.destroy(scope);
}
}

// Reset to initial state
self.scope = null;
self.allocator = null;
self.is_alive = true;
}
};

var global_scope_wrapper = GlobalScopeWrapper.init();

threadlocal var thread_isolation_scope: ?*Scope = null;
threadlocal var thread_current_scope_stack: ?*ArrayList(*Scope) = null;
Expand All @@ -460,16 +551,7 @@ const ScopeManager = struct {
}

fn getGlobalScope(self: *ScopeManager) !*Scope {
global_scope_mutex.lock();
defer global_scope_mutex.unlock();

if (global_scope == null) {
const scope = try self.allocator.create(Scope);
scope.* = Scope.init(self.allocator);
global_scope = scope;
}

return global_scope.?;
return try global_scope_wrapper.getOrCreate(self.allocator);
}

fn getIsolationScope(self: *ScopeManager) !*Scope {
Expand Down Expand Up @@ -545,16 +627,9 @@ pub fn initScopeManager(allocator: Allocator) !void {

/// Deinitialize the global scope manager and clean up all resources
pub fn deinitScopeManager() void {
if (g_scope_manager) |*manager| {
// Clean up global scope
global_scope_mutex.lock();
defer global_scope_mutex.unlock();

if (global_scope) |scope| {
scope.deinit();
manager.allocator.destroy(scope);
global_scope = null;
}
if (g_scope_manager != null) {
// Clean up global scope using the wrapper
global_scope_wrapper.deinit();
Comment thread
Litarnus marked this conversation as resolved.

// Note: Thread-local scopes should be cleaned up by their respective threads
// before calling this function. We can't safely clean them up here.
Expand Down Expand Up @@ -673,14 +748,8 @@ pub fn captureEvent(event: Event) !?EventId {
}

fn resetAllScopeState(allocator: std.mem.Allocator) void {
global_scope_mutex.lock();
defer global_scope_mutex.unlock();

if (global_scope) |scope| {
scope.deinit();
allocator.destroy(scope);
global_scope = null;
}
// Reset the global scope wrapper to initial state (keeps same mutex)
global_scope_wrapper.reset();

if (thread_isolation_scope) |scope| {
scope.deinit();
Expand Down
Loading