Skip to content

fix: Don't overwrite MainThreadId #2165

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

- The SDK no longer attaches screenshots when capturing errors in the Unity Editor. ([#2163](https://github.com/getsentry/sentry-unity/pull/2163))

## Fixes

- Fixed a potential race condition that when targeting Android could cause 'attempting to detach while still running code' crashes ([#2165](https://github.com/getsentry/sentry-unity/pull/2165))

### Dependencies

- Bump Java SDK from v8.11.1 to v8.12.0 ([#2155](https://github.com/getsentry/sentry-unity/pull/2155))
Expand Down
2 changes: 1 addition & 1 deletion package-dev/Runtime/SentryInitialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ private static void SetupNativeSdk(SentryUnityOptions options, SentryUnityInfo u
#elif SENTRY_NATIVE
SentryNative.Configure(options, unityInfo);
#elif SENTRY_WEBGL
SentryWebGL.Configure(options);
SentryWebGL.Configure(options);
#endif
}
catch (DllNotFoundException e)
Expand Down
6 changes: 5 additions & 1 deletion samples/unity-of-bugs/Assets/Scripts/BugFarmButtons.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Sentry;
using UnityEngine;
using UnityEngine.Assertions;
Expand All @@ -15,7 +17,9 @@ private void Awake()
private void Start()
{
Debug.Log("Sample Start 🦋");
Debug.LogWarning("Here come the bugs 🐞🦋🐛🐜🕷!");
Debug.LogWarning("Here come the bugs 🐞🦋🐛🐜!");

Task.Run(() => { Debug.Log("The spider snuck up from a task! 🕷"); });
}

public void AssertFalse() => Assert.AreEqual(true, false);
Expand Down
17 changes: 13 additions & 4 deletions src/Sentry.Unity/MainThreadData.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Threading;
using UnityEngine;

namespace Sentry.Unity;

Expand Down Expand Up @@ -69,8 +68,16 @@ internal static class MainThreadData

public static DateTimeOffset? StartTime { get; set; }

public static bool IsMainThread()
=> MainThreadId.HasValue && Thread.CurrentThread.ManagedThreadId == MainThreadId;
public static bool? IsMainThread()
{
if (MainThreadId.HasValue)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it’s an integer that should be set once and visible across threads, I think declaring it as volatile makes sense:

internal static volatile int _mainThreadId;

If you really need to make it nullable, then this should also work:

private static int? _mainThreadId;

internal static int? MainThreadId
{
    get => Volatile.Read(ref _mainThreadId);
    set => Volatile.Write(ref _mainThreadId, value);
}

{
return MainThreadId.Equals(Thread.CurrentThread.ManagedThreadId);
}

// We don't know whether this is the main thread or not
return null;
}

// For testing
internal static ISentrySystemInfo? SentrySystemInfo { get; set; }
Expand All @@ -79,7 +86,9 @@ public static void CollectData()
{
var sentrySystemInfo = SentrySystemInfo ?? SentrySystemInfoAdapter.Instance;

MainThreadId = sentrySystemInfo.MainThreadId;
// Don't overwrite the MainThreadId if it's already been set
MainThreadId ??= sentrySystemInfo.MainThreadId;

ProcessorCount = sentrySystemInfo.ProcessorCount;
OperatingSystem = sentrySystemInfo.OperatingSystem;
CpuDescription = sentrySystemInfo.CpuDescription;
Expand Down
2 changes: 1 addition & 1 deletion src/Sentry.Unity/ScreenshotEventProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ internal ScreenshotEventProcessor(SentryUnityOptions sentryOptions, IApplication

public SentryEvent? Process(SentryEvent @event, SentryHint hint)
{
if (!MainThreadData.IsMainThread())
if (MainThreadData.IsMainThread() is not true)
{
_options.DiagnosticLogger?.LogDebug("Screenshot capture skipped. Can't capture screenshots on other than the main thread.");
return @event;
Expand Down
4 changes: 2 additions & 2 deletions src/Sentry.Unity/SentryUnitySDK.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ private SentryUnitySdk(SentryUnityOptions options)
return null;
}

MainThreadData.CollectData();

// On Standalone, we disable cache dir in case multiple app instances run over the same path.
// Note: we cannot use a named Mutex, because Unit doesn't support it. Instead, we create a file with `FileShare.None`.
// https://forum.unity.com/threads/unsupported-internal-call-for-il2cpp-mutex-createmutex_internal-named-mutexes-are-not-supported.387334/
Expand All @@ -49,6 +47,8 @@ private SentryUnitySdk(SentryUnityOptions options)
}
}

MainThreadData.CollectData();

unitySdk._dotnetSdk = SentrySdk.Init(options);

if (options.NativeContextWriter is { } contextWriter)
Expand Down
12 changes: 11 additions & 1 deletion src/Sentry.Unity/UnityEventProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ private void SetEventContext(IEventLike sentryEvent)

private void PopulateDevice(Device device)
{
if (!MainThreadData.IsMainThread())
if (MainThreadData.IsMainThread() is not true)
{
return;
}
Expand Down Expand Up @@ -93,4 +93,14 @@ private void PopulateSdkIntegrations(SdkVersion sdkVersion)
internal static class TagValueNormalizer
{
internal static string ToTagValue(this bool value) => value ? "true" : "false";

internal static string ToTagValue(this bool? value)
{
if (value.HasValue)
{
return value.Value ? "true" : "false";
}

return "unknown";
}
}
2 changes: 1 addition & 1 deletion src/Sentry.Unity/ViewHierarchyEventProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public ViewHierarchyEventProcessor(SentryUnityOptions sentryOptions)

public SentryEvent? Process(SentryEvent @event, SentryHint hint)
{
if (!MainThreadData.IsMainThread())
if (MainThreadData.IsMainThread() is not true)
{
_options.DiagnosticLogger?.LogDebug("Hierarchy capture skipped. Can't capture hierarchy on other than the main thread.");
return @event;
Expand Down
1 change: 1 addition & 0 deletions test/Sentry.Unity.Tests/UnityEventScopeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ public void AppProtocol_Assigned()
_testApplication = new TestApplication(productName: "TestGame");
var sut = new UnityScopeUpdater(_sentryOptions, _testApplication);
var scope = new Scope(_sentryOptions);
MainThreadData.CollectData();

// act
sut.ConfigureScope(scope);
Expand Down
Loading