From 8f477b00da8a503ef597099119e6957f663587d9 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 1 Sep 2024 10:59:19 -0700 Subject: [PATCH] renderer/termio attach thread local state for crash capture --- src/crash/sentry.zig | 15 +++++---------- src/renderer/Thread.zig | 7 +++++++ src/termio/Thread.zig | 7 +++++++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/crash/sentry.zig b/src/crash/sentry.zig index 6b649e713..f1ab7b700 100644 --- a/src/crash/sentry.zig +++ b/src/crash/sentry.zig @@ -29,7 +29,7 @@ pub const ThreadState = struct { /// See ThreadState. This should only ever be set by the owner of the /// thread entry function. -threadlocal var thread_state: ?ThreadState = null; +pub threadlocal var thread_state: ?ThreadState = null; /// Process-wide initialization of our Sentry client. /// @@ -140,15 +140,10 @@ fn beforeSend( // handler to set thread-specific data such as window size, grid size, // etc. that we can use to debug crashes. - const thr_state = thread_state orelse { - // If we don't have thread state we note this in the context - // so we can see that but don't do anything else. - const obj = sentry.Value.initObject(); - errdefer obj.decref(); - obj.setByKey("unknown", sentry.Value.initBool(true)); - sentry.setContext("surface", obj); - return event_val; - }; + // If we don't have thread state we can't reliably determine + // metadata such as surface dimensions. In the future we can probably + // drop full app state (all surfaces, all windows, etc.). + const thr_state = thread_state orelse return event_val; // Read the surface data. This is likely unsafe because on a crash // other threads can continue running. We don't have race-safe way to diff --git a/src/renderer/Thread.zig b/src/renderer/Thread.zig index 2521d18a4..1b730693b 100644 --- a/src/renderer/Thread.zig +++ b/src/renderer/Thread.zig @@ -5,6 +5,7 @@ pub const Thread = @This(); const std = @import("std"); const builtin = @import("builtin"); const xev = @import("xev"); +const crash = @import("../crash/main.zig"); const renderer = @import("../renderer.zig"); const apprt = @import("../apprt.zig"); const configpkg = @import("../config.zig"); @@ -191,6 +192,12 @@ pub fn threadMain(self: *Thread) void { fn threadMain_(self: *Thread) !void { defer log.debug("renderer thread exited", .{}); + // Setup our crash metadata + crash.sentry.thread_state = .{ + .surface = self.renderer.surface_mailbox.surface, + }; + defer crash.sentry.thread_state = null; + // Run our loop start/end callbacks if the renderer cares. const has_loop = @hasDecl(renderer.Renderer, "loopEnter"); if (has_loop) try self.renderer.loopEnter(self); diff --git a/src/termio/Thread.zig b/src/termio/Thread.zig index 94650aef6..d38c6a1ce 100644 --- a/src/termio/Thread.zig +++ b/src/termio/Thread.zig @@ -15,6 +15,7 @@ const std = @import("std"); const ArenaAllocator = std.heap.ArenaAllocator; const builtin = @import("builtin"); const xev = @import("xev"); +const crash = @import("../crash/main.zig"); const termio = @import("../termio.zig"); const BlockingQueue = @import("../blocking_queue.zig").BlockingQueue; @@ -200,6 +201,12 @@ pub fn threadMain(self: *Thread, io: *termio.Termio) void { fn threadMain_(self: *Thread, io: *termio.Termio) !void { defer log.debug("IO thread exited", .{}); + // Setup our crash metadata + crash.sentry.thread_state = .{ + .surface = io.surface_mailbox.surface, + }; + defer crash.sentry.thread_state = null; + // Get the mailbox. This must be an SPSC mailbox for threading. const mailbox = switch (io.mailbox) { .spsc => |*v| v,