diff --git a/src/ZeroLog.Impl.Base/LogManager.cs b/src/ZeroLog.Impl.Base/LogManager.cs
index 4f8aa28..3977922 100644
--- a/src/ZeroLog.Impl.Base/LogManager.cs
+++ b/src/ZeroLog.Impl.Base/LogManager.cs
@@ -20,6 +20,9 @@ public sealed partial class LogManager
///
/// The type.
public static Log GetLogger()
+#if NET9_0_OR_GREATER
+ where T : allows ref struct
+#endif
=> GetLogger(typeof(T));
///
diff --git a/src/ZeroLog.Impl.Full/BufferSegmentProvider.cs b/src/ZeroLog.Impl.Full/BufferSegmentProvider.cs
index cb4b000..ffb19dc 100644
--- a/src/ZeroLog.Impl.Full/BufferSegmentProvider.cs
+++ b/src/ZeroLog.Impl.Full/BufferSegmentProvider.cs
@@ -4,7 +4,11 @@ namespace ZeroLog;
internal unsafe class BufferSegmentProvider
{
- private readonly object _lock = new();
+#if NET9_0_OR_GREATER
+ private static readonly System.Threading.Lock _lock = new();
+#else
+ private static readonly object _lock = new();
+#endif
private readonly int _segmentCount;
private readonly int _segmentSize;
diff --git a/src/ZeroLog.Impl.Full/Runner.cs b/src/ZeroLog.Impl.Full/Runner.cs
index 42d1473..754ae96 100644
--- a/src/ZeroLog.Impl.Full/Runner.cs
+++ b/src/ZeroLog.Impl.Full/Runner.cs
@@ -310,7 +310,11 @@ public override void Flush()
internal sealed class SyncRunner(ZeroLogConfiguration config) : Runner(config)
{
- private readonly object _lock = new();
+#if NET9_0_OR_GREATER
+ private static readonly Lock _lock = new();
+#else
+ private static readonly object _lock = new();
+#endif
public override void Submit(LogMessage message)
{
diff --git a/src/ZeroLog.Impl.Full/UnmanagedCache.cs b/src/ZeroLog.Impl.Full/UnmanagedCache.cs
index a1bfab3..9a73f40 100644
--- a/src/ZeroLog.Impl.Full/UnmanagedCache.cs
+++ b/src/ZeroLog.Impl.Full/UnmanagedCache.cs
@@ -31,6 +31,12 @@ internal delegate bool FormatterDelegate(
ZeroLogConfiguration config
);
+#if NET9_0_OR_GREATER
+ private static readonly System.Threading.Lock _lock = new();
+#else
+ private static readonly object _lock = new();
+#endif
+
private static readonly Dictionary _unmanagedStructs = new();
private static readonly MethodInfo _registerMethod = typeof(UnmanagedCache).GetMethod(nameof(Register), Type.EmptyTypes)!;
@@ -52,7 +58,7 @@ public static void Register(UnmanagedFormatterDelegate formatter)
{
ArgumentNullException.ThrowIfNull(formatter);
- lock (_unmanagedStructs)
+ lock (_lock)
{
_unmanagedStructs[typeof(T).TypeHandle.Value] = (byte* valuePtr, Span destination, out int charsWritten, ReadOnlySpan format, ZeroLogConfiguration _)
=> FormatterGeneric(valuePtr, destination, out charsWritten, format, formatter);
@@ -109,7 +115,7 @@ private static bool FormatterGenericNullable(byte* valuePtr,
public static bool TryGetFormatter(IntPtr typeHandle, out FormatterDelegate formatter)
{
// This is accessed from a single thread, there should be no contention
- lock (_unmanagedStructs)
+ lock (_lock)
{
return _unmanagedStructs.TryGetValue(typeHandle, out formatter!);
}
diff --git a/src/ZeroLog.Tests/PerformanceTests.cs b/src/ZeroLog.Tests/PerformanceTests.cs
index 59ecf01..9c60de9 100644
--- a/src/ZeroLog.Tests/PerformanceTests.cs
+++ b/src/ZeroLog.Tests/PerformanceTests.cs
@@ -55,7 +55,7 @@ public void should_run_test()
var signal = _testAppender.SetMessageCountTarget(totalMessageCount);
var utcNow = DateTime.UtcNow;
- Parallel.For(0, threadCount, i =>
+ Parallel.For(0, threadCount, _ =>
{
for (var k = 0; k < threadMessageCount; k++)
{
diff --git a/src/ZeroLog.Tests/Support/AssertExtensions.cs b/src/ZeroLog.Tests/Support/AssertExtensions.cs
index 5bffecb..3e8cee4 100644
--- a/src/ZeroLog.Tests/Support/AssertExtensions.cs
+++ b/src/ZeroLog.Tests/Support/AssertExtensions.cs
@@ -7,6 +7,9 @@ namespace ZeroLog.Tests.Support;
#nullable enable
+#if NET6_0_OR_GREATER
+[System.Diagnostics.StackTraceHidden]
+#endif
internal static class AssertExtensions
{
public static void ShouldEqual(this T? actual, T? expected)