Skip to content

Commit

Permalink
[NativeAOT] Fix Lock's usage of NativeRuntimeEventSource.Log to accou…
Browse files Browse the repository at this point in the history
…nt for recursive accesses during its own class construction (dotnet#94873)

* Fix Lock's usage of NativeRuntimeEventSource.Log to account for recursive accesses during its own class construction

- `NativeRuntimeEventSource.Log` can be null if it's being constructed in the same thread earlier in the stack, added null checks

Fixes dotnet#94728
  • Loading branch information
kouvel authored and tmds committed Jan 23, 2024
1 parent e27a232 commit fa1cf85
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ private static bool TryInitializeStatics()
s_minSpinCount = DetermineMinSpinCount();

// Also initialize some types that are used later to prevent potential class construction cycles
NativeRuntimeEventSource.Log.IsEnabled();
_ = NativeRuntimeEventSource.Log;
}
catch
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -444,9 +444,9 @@ private ThreadId TryEnterSlow(int timeoutMs, ThreadId currentThreadId)

Wait:
bool areContentionEventsEnabled =
NativeRuntimeEventSource.Log.IsEnabled(
NativeRuntimeEventSource.Log?.IsEnabled(
EventLevel.Informational,
NativeRuntimeEventSource.Keywords.ContentionKeyword);
NativeRuntimeEventSource.Keywords.ContentionKeyword) ?? false;
AutoResetEvent waitEvent = _waitEvent ?? CreateWaitEvent(areContentionEventsEnabled);
if (State.TryLockBeforeWait(this))
{
Expand All @@ -463,7 +463,7 @@ private ThreadId TryEnterSlow(int timeoutMs, ThreadId currentThreadId)
long waitStartTimeTicks = 0;
if (areContentionEventsEnabled)
{
NativeRuntimeEventSource.Log.ContentionStart(this);
NativeRuntimeEventSource.Log!.ContentionStart(this);
waitStartTimeTicks = Stopwatch.GetTimestamp();
}

Expand Down Expand Up @@ -535,7 +535,7 @@ private ThreadId TryEnterSlow(int timeoutMs, ThreadId currentThreadId)
{
double waitDurationNs =
(Stopwatch.GetTimestamp() - waitStartTimeTicks) * 1_000_000_000.0 / Stopwatch.Frequency;
NativeRuntimeEventSource.Log.ContentionStop(waitDurationNs);
NativeRuntimeEventSource.Log!.ContentionStop(waitDurationNs);
}

return currentThreadId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ internal bool WaitOneNoCheck(
#if !CORECLR // CoreCLR sends the wait events from the native side
bool sendWaitEvents =
millisecondsTimeout != 0 &&
#if NATIVEAOT
// A null check is necessary in NativeAOT due to the possibility of reentrance during class
// construction, as this path can be reached through Lock. See
// https://github.com/dotnet/runtime/issues/94728 for a call stack.
NativeRuntimeEventSource.Log != null &&
#endif
NativeRuntimeEventSource.Log.IsEnabled(
EventLevel.Verbose,
NativeRuntimeEventSource.Keywords.WaitHandleKeyword);
Expand Down

0 comments on commit fa1cf85

Please sign in to comment.