From 6acde78f5bd25b34e6026d97e513b157c16ce8be Mon Sep 17 00:00:00 2001 From: Mark Cilia Vincenti Date: Mon, 26 Aug 2024 11:59:55 +0200 Subject: [PATCH 1/4] Encourage use of .NET 9.0's System.Threading.Lock --- build-common/NHibernate.props | 2 +- .../NHSpecificTest/NH2030/Fixture.cs | 4 ++-- .../NHSpecificTest/NH2192/Fixture.cs | 2 +- src/NHibernate/Cache/SyncCacheLock.cs | 13 ++++--------- src/NHibernate/Cache/Timestamper.cs | 3 ++- src/NHibernate/Context/MapBasedSessionContext.cs | 3 ++- src/NHibernate/NHibernate.csproj | 4 ++++ src/NHibernate/Stat/StatisticsImpl.cs | 3 ++- src/NHibernate/Util/SimpleMRUCache.cs | 3 ++- src/NHibernate/Util/SoftLimitMRUCache.cs | 3 ++- 10 files changed, 22 insertions(+), 18 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index c2676d0cd85..4ea65f60e48 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -6,7 +6,7 @@ 0 dev - 12.0 + preview $(NhVersion).$(VersionPatch) $(VersionSuffix).$(BuildNumber) diff --git a/src/NHibernate.Test/NHSpecificTest/NH2030/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2030/Fixture.cs index dba4873091e..a8ab396cbc6 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2030/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2030/Fixture.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Text; @@ -15,7 +15,7 @@ public class Fixture [Test] public void GetTypeWithLenShouldBeThreadSafe() { - object sync = new object(); + Lock sync = new Lock(); List exceptions = new List(); ManualResetEvent startEvent = new ManualResetEvent(false); diff --git a/src/NHibernate.Test/NHSpecificTest/NH2192/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2192/Fixture.cs index bf63c8c391f..94ef1d39bfa 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2192/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2192/Fixture.cs @@ -45,7 +45,7 @@ protected override void OnTearDown() [Test] public void HqlIsThreadsafe_UsingThreads() { - object sync = new object(); + Lock sync = new Lock(); List results = new List(); List exceptions = new List(); diff --git a/src/NHibernate/Cache/SyncCacheLock.cs b/src/NHibernate/Cache/SyncCacheLock.cs index c9eceacb63c..912dd20e8a8 100644 --- a/src/NHibernate/Cache/SyncCacheLock.cs +++ b/src/NHibernate/Cache/SyncCacheLock.cs @@ -10,28 +10,23 @@ class SyncCacheLock : ICacheLock class MonitorLock : IDisposable { - private readonly object _lockObj; - - public MonitorLock(object lockObj) - { - _lockObj = lockObj; - } + private readonly Lock _lockObj = new Lock(); public IDisposable Lock() { - Monitor.Enter(_lockObj); + _lockObj.Enter(); return this; } public void Dispose() { - Monitor.Exit(_lockObj); + _lockObj.Exit(); } } public SyncCacheLock() { - _monitorLock = new MonitorLock(this); + _monitorLock = new(); } public void Dispose() diff --git a/src/NHibernate/Cache/Timestamper.cs b/src/NHibernate/Cache/Timestamper.cs index c904b9108b4..c8b5bca4e62 100644 --- a/src/NHibernate/Cache/Timestamper.cs +++ b/src/NHibernate/Cache/Timestamper.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; namespace NHibernate.Cache { @@ -11,7 +12,7 @@ namespace NHibernate.Cache /// public static class Timestamper { - private static object lockObject = new object(); + private static Lock lockObject = new Lock(); // hibernate is using System.currentMilliSeconds which is calculated // from jan 1, 1970 diff --git a/src/NHibernate/Context/MapBasedSessionContext.cs b/src/NHibernate/Context/MapBasedSessionContext.cs index 60f67ae7697..4d50871195d 100644 --- a/src/NHibernate/Context/MapBasedSessionContext.cs +++ b/src/NHibernate/Context/MapBasedSessionContext.cs @@ -1,5 +1,6 @@ using System.Collections; using System.Collections.Concurrent; +using System.Threading; using NHibernate.Engine; namespace NHibernate.Context @@ -9,7 +10,7 @@ public abstract class MapBasedSessionContext : CurrentSessionContext private readonly ISessionFactoryImplementor _factory; // Must be static, different instances of MapBasedSessionContext may have to yield the same map. - private static readonly object _locker = new object(); + private static readonly Lock _locker = new Lock(); protected MapBasedSessionContext(ISessionFactoryImplementor factory) { diff --git a/src/NHibernate/NHibernate.csproj b/src/NHibernate/NHibernate.csproj index e38db30c036..ce8d19db95b 100644 --- a/src/NHibernate/NHibernate.csproj +++ b/src/NHibernate/NHibernate.csproj @@ -73,6 +73,10 @@ + + + + ./ diff --git a/src/NHibernate/Stat/StatisticsImpl.cs b/src/NHibernate/Stat/StatisticsImpl.cs index b7d055dc9e0..7cf09bd53b3 100644 --- a/src/NHibernate/Stat/StatisticsImpl.cs +++ b/src/NHibernate/Stat/StatisticsImpl.cs @@ -3,12 +3,13 @@ using System.Text; using NHibernate.Engine; using System.Linq; +using System.Threading; namespace NHibernate.Stat { public class StatisticsImpl : IStatistics, IStatisticsImplementor { - private readonly object _syncRoot = new object(); + private readonly Lock _syncRoot = new Lock(); private static readonly INHibernateLogger log = NHibernateLogger.For(typeof(StatisticsImpl)); private readonly ISessionFactoryImplementor sessionFactory; diff --git a/src/NHibernate/Util/SimpleMRUCache.cs b/src/NHibernate/Util/SimpleMRUCache.cs index b6ad7beb413..0f1d590dab8 100644 --- a/src/NHibernate/Util/SimpleMRUCache.cs +++ b/src/NHibernate/Util/SimpleMRUCache.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.Serialization; +using System.Threading; namespace NHibernate.Util { @@ -17,7 +18,7 @@ public class SimpleMRUCache : IDeserializationCallback { private const int DefaultStrongRefCount = 128; - private readonly object _syncRoot = new object(); + private readonly Lock _syncRoot = new Lock(); private readonly int strongReferenceCount; diff --git a/src/NHibernate/Util/SoftLimitMRUCache.cs b/src/NHibernate/Util/SoftLimitMRUCache.cs index e69c3f2916e..221369db0ed 100644 --- a/src/NHibernate/Util/SoftLimitMRUCache.cs +++ b/src/NHibernate/Util/SoftLimitMRUCache.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Runtime.Serialization; +using System.Threading; namespace NHibernate.Util { @@ -23,7 +24,7 @@ namespace NHibernate.Util public class SoftLimitMRUCache : IDeserializationCallback { private const int DefaultStrongRefCount = 128; - private readonly object _syncRoot = new object(); + private readonly Lock _syncRoot = new Lock(); private readonly int strongReferenceCount; From f38a82cf4481d7b9e047c7432ea434a6a5ad0450 Mon Sep 17 00:00:00 2001 From: Mark Cilia Vincenti Date: Sun, 1 Sep 2024 19:56:08 +0200 Subject: [PATCH 2/4] PR changes --- src/NHibernate.Test/NHSpecificTest/NH2030/Fixture.cs | 2 +- src/NHibernate.Test/NHSpecificTest/NH2192/Fixture.cs | 2 +- src/NHibernate/Cache/SyncCacheLock.cs | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/NH2030/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2030/Fixture.cs index a8ab396cbc6..d3f377e9e59 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2030/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2030/Fixture.cs @@ -15,7 +15,7 @@ public class Fixture [Test] public void GetTypeWithLenShouldBeThreadSafe() { - Lock sync = new Lock(); + object sync = new object(); List exceptions = new List(); ManualResetEvent startEvent = new ManualResetEvent(false); diff --git a/src/NHibernate.Test/NHSpecificTest/NH2192/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2192/Fixture.cs index 94ef1d39bfa..bf63c8c391f 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2192/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2192/Fixture.cs @@ -45,7 +45,7 @@ protected override void OnTearDown() [Test] public void HqlIsThreadsafe_UsingThreads() { - Lock sync = new Lock(); + object sync = new object(); List results = new List(); List exceptions = new List(); diff --git a/src/NHibernate/Cache/SyncCacheLock.cs b/src/NHibernate/Cache/SyncCacheLock.cs index 912dd20e8a8..2cc4656a2fb 100644 --- a/src/NHibernate/Cache/SyncCacheLock.cs +++ b/src/NHibernate/Cache/SyncCacheLock.cs @@ -6,9 +6,9 @@ namespace NHibernate.Cache { class SyncCacheLock : ICacheLock { - private readonly MonitorLock _monitorLock; + private readonly InternalLock _internalLock; - class MonitorLock : IDisposable + class InternalLock : IDisposable { private readonly Lock _lockObj = new Lock(); @@ -26,7 +26,7 @@ public void Dispose() public SyncCacheLock() { - _monitorLock = new(); + _internalLock = new(); } public void Dispose() @@ -35,12 +35,12 @@ public void Dispose() public IDisposable ReadLock() { - return _monitorLock.Lock(); + return _internalLock.Lock(); } public IDisposable WriteLock() { - return _monitorLock.Lock(); + return _internalLock.Lock(); } public Task ReadLockAsync() From b3acc385f63bd4684e117274235697e0fbc964a8 Mon Sep 17 00:00:00 2001 From: Mark Cilia Vincenti Date: Tue, 31 Dec 2024 09:20:06 +0100 Subject: [PATCH 3/4] Used source generator instead. --- build-common/NHibernate.props | 2 +- src/NHibernate/Cache/Timestamper.cs | 2 +- .../Context/MapBasedSessionContext.cs | 2 +- src/NHibernate/NHibernate.csproj | 10 ++++++++-- src/NHibernate/Stat/StatisticsImpl.cs | 2 +- src/NHibernate/Util/AsyncReaderWriterLock.cs | 17 +++++++++-------- src/NHibernate/Util/SimpleMRUCache.cs | 2 +- src/NHibernate/Util/SoftLimitMRUCache.cs | 2 +- 8 files changed, 23 insertions(+), 16 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index 4ea65f60e48..4fa8208b537 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -6,7 +6,7 @@ 0 dev - preview + 13.0 $(NhVersion).$(VersionPatch) $(VersionSuffix).$(BuildNumber) diff --git a/src/NHibernate/Cache/Timestamper.cs b/src/NHibernate/Cache/Timestamper.cs index c8b5bca4e62..159ce788593 100644 --- a/src/NHibernate/Cache/Timestamper.cs +++ b/src/NHibernate/Cache/Timestamper.cs @@ -12,7 +12,7 @@ namespace NHibernate.Cache /// public static class Timestamper { - private static Lock lockObject = new Lock(); + private static Lock lockObject = LockFactory.Create(); // hibernate is using System.currentMilliSeconds which is calculated // from jan 1, 1970 diff --git a/src/NHibernate/Context/MapBasedSessionContext.cs b/src/NHibernate/Context/MapBasedSessionContext.cs index 4d50871195d..275d38febe9 100644 --- a/src/NHibernate/Context/MapBasedSessionContext.cs +++ b/src/NHibernate/Context/MapBasedSessionContext.cs @@ -10,7 +10,7 @@ public abstract class MapBasedSessionContext : CurrentSessionContext private readonly ISessionFactoryImplementor _factory; // Must be static, different instances of MapBasedSessionContext may have to yield the same map. - private static readonly Lock _locker = new Lock(); + private static readonly Lock _locker = LockFactory.Create(); protected MapBasedSessionContext(ISessionFactoryImplementor factory) { diff --git a/src/NHibernate/NHibernate.csproj b/src/NHibernate/NHibernate.csproj index ce8d19db95b..bcc078ff91f 100644 --- a/src/NHibernate/NHibernate.csproj +++ b/src/NHibernate/NHibernate.csproj @@ -73,8 +73,14 @@ - - + + + all + analyzers + + + + diff --git a/src/NHibernate/Stat/StatisticsImpl.cs b/src/NHibernate/Stat/StatisticsImpl.cs index 7cf09bd53b3..7641a337d44 100644 --- a/src/NHibernate/Stat/StatisticsImpl.cs +++ b/src/NHibernate/Stat/StatisticsImpl.cs @@ -9,7 +9,7 @@ namespace NHibernate.Stat { public class StatisticsImpl : IStatistics, IStatisticsImplementor { - private readonly Lock _syncRoot = new Lock(); + private readonly Lock _syncRoot = LockFactory.Create(); private static readonly INHibernateLogger log = NHibernateLogger.For(typeof(StatisticsImpl)); private readonly ISessionFactoryImplementor sessionFactory; diff --git a/src/NHibernate/Util/AsyncReaderWriterLock.cs b/src/NHibernate/Util/AsyncReaderWriterLock.cs index 203de8812ee..74cd897a731 100644 --- a/src/NHibernate/Util/AsyncReaderWriterLock.cs +++ b/src/NHibernate/Util/AsyncReaderWriterLock.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; @@ -9,6 +9,7 @@ namespace NHibernate.Util // https://devblogs.microsoft.com/pfxteam/building-async-coordination-primitives-part-7-asyncreaderwriterlock/ internal class AsyncReaderWriterLock : IDisposable, Cache.ICacheLock { + private readonly Lock _writeLockLock = LockFactory.Create(); private readonly SemaphoreSlim _writeLockSemaphore = new SemaphoreSlim(1, 1); private readonly SemaphoreSlim _readLockSemaphore = new SemaphoreSlim(0, 1); private readonly Releaser _writerReleaser; @@ -48,7 +49,7 @@ public Releaser WriteLock() if (!CanEnterWriteLock(out var waitForReadLocks)) { _writeLockSemaphore.Wait(); - lock (_writeLockSemaphore) + lock (_writeLockLock) { _writersWaiting--; } @@ -74,7 +75,7 @@ public async Task WriteLockAsync() if (!CanEnterWriteLock(out var waitForReadLocks)) { await _writeLockSemaphore.WaitAsync().ConfigureAwait(false); - lock (_writeLockSemaphore) + lock (_writeLockLock) { _writersWaiting--; } @@ -126,7 +127,7 @@ async Task ReadLockInternalAsync() public void Dispose() { - lock (_writeLockSemaphore) + lock (_writeLockLock) { _writeLockSemaphore.Dispose(); _readLockSemaphore.Dispose(); @@ -139,7 +140,7 @@ public void Dispose() private bool CanEnterWriteLock(out bool waitForReadLocks) { waitForReadLocks = false; - lock (_writeLockSemaphore) + lock (_writeLockLock) { AssertNotDisposed(); if (_writeLockSemaphore.CurrentCount > 0 && _writeLockSemaphore.Wait(0)) @@ -156,7 +157,7 @@ private bool CanEnterWriteLock(out bool waitForReadLocks) private void ExitWriteLock() { - lock (_writeLockSemaphore) + lock (_writeLockLock) { AssertNotDisposed(); if (_writeLockSemaphore.CurrentCount == 1) @@ -187,7 +188,7 @@ private void ExitWriteLock() private bool CanEnterReadLock(out SemaphoreSlim waitingReadLockSemaphore) { - lock (_writeLockSemaphore) + lock (_writeLockLock) { AssertNotDisposed(); if (_writersWaiting == 0 && _writeLockSemaphore.CurrentCount > 0) @@ -212,7 +213,7 @@ private bool CanEnterReadLock(out SemaphoreSlim waitingReadLockSemaphore) private void ExitReadLock() { - lock (_writeLockSemaphore) + lock (_writeLockLock) { AssertNotDisposed(); if (_currentReaders == 0) diff --git a/src/NHibernate/Util/SimpleMRUCache.cs b/src/NHibernate/Util/SimpleMRUCache.cs index 0f1d590dab8..d7f8eb07409 100644 --- a/src/NHibernate/Util/SimpleMRUCache.cs +++ b/src/NHibernate/Util/SimpleMRUCache.cs @@ -18,7 +18,7 @@ public class SimpleMRUCache : IDeserializationCallback { private const int DefaultStrongRefCount = 128; - private readonly Lock _syncRoot = new Lock(); + private readonly Lock _syncRoot = LockFactory.Create(); private readonly int strongReferenceCount; diff --git a/src/NHibernate/Util/SoftLimitMRUCache.cs b/src/NHibernate/Util/SoftLimitMRUCache.cs index 221369db0ed..3b4e67cf61e 100644 --- a/src/NHibernate/Util/SoftLimitMRUCache.cs +++ b/src/NHibernate/Util/SoftLimitMRUCache.cs @@ -24,7 +24,7 @@ namespace NHibernate.Util public class SoftLimitMRUCache : IDeserializationCallback { private const int DefaultStrongRefCount = 128; - private readonly Lock _syncRoot = new Lock(); + private readonly Lock _syncRoot = LockFactory.Create(); private readonly int strongReferenceCount; From 45b3b51513b368d4b83f493fa0cff3e5d9755913 Mon Sep 17 00:00:00 2001 From: Mark Cilia Vincenti Date: Tue, 31 Dec 2024 09:27:21 +0100 Subject: [PATCH 4/4] Fix --- src/NHibernate/Util/AsyncReaderWriterLock.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/NHibernate/Util/AsyncReaderWriterLock.cs b/src/NHibernate/Util/AsyncReaderWriterLock.cs index 74cd897a731..c6b1287a80b 100644 --- a/src/NHibernate/Util/AsyncReaderWriterLock.cs +++ b/src/NHibernate/Util/AsyncReaderWriterLock.cs @@ -9,7 +9,6 @@ namespace NHibernate.Util // https://devblogs.microsoft.com/pfxteam/building-async-coordination-primitives-part-7-asyncreaderwriterlock/ internal class AsyncReaderWriterLock : IDisposable, Cache.ICacheLock { - private readonly Lock _writeLockLock = LockFactory.Create(); private readonly SemaphoreSlim _writeLockSemaphore = new SemaphoreSlim(1, 1); private readonly SemaphoreSlim _readLockSemaphore = new SemaphoreSlim(0, 1); private readonly Releaser _writerReleaser; @@ -49,7 +48,7 @@ public Releaser WriteLock() if (!CanEnterWriteLock(out var waitForReadLocks)) { _writeLockSemaphore.Wait(); - lock (_writeLockLock) + lock (_writeLockSemaphore) { _writersWaiting--; } @@ -75,7 +74,7 @@ public async Task WriteLockAsync() if (!CanEnterWriteLock(out var waitForReadLocks)) { await _writeLockSemaphore.WaitAsync().ConfigureAwait(false); - lock (_writeLockLock) + lock (_writeLockSemaphore) { _writersWaiting--; } @@ -127,7 +126,7 @@ async Task ReadLockInternalAsync() public void Dispose() { - lock (_writeLockLock) + lock (_writeLockSemaphore) { _writeLockSemaphore.Dispose(); _readLockSemaphore.Dispose(); @@ -140,7 +139,7 @@ public void Dispose() private bool CanEnterWriteLock(out bool waitForReadLocks) { waitForReadLocks = false; - lock (_writeLockLock) + lock (_writeLockSemaphore) { AssertNotDisposed(); if (_writeLockSemaphore.CurrentCount > 0 && _writeLockSemaphore.Wait(0)) @@ -157,7 +156,7 @@ private bool CanEnterWriteLock(out bool waitForReadLocks) private void ExitWriteLock() { - lock (_writeLockLock) + lock (_writeLockSemaphore) { AssertNotDisposed(); if (_writeLockSemaphore.CurrentCount == 1) @@ -188,7 +187,7 @@ private void ExitWriteLock() private bool CanEnterReadLock(out SemaphoreSlim waitingReadLockSemaphore) { - lock (_writeLockLock) + lock (_writeLockSemaphore) { AssertNotDisposed(); if (_writersWaiting == 0 && _writeLockSemaphore.CurrentCount > 0) @@ -213,7 +212,7 @@ private bool CanEnterReadLock(out SemaphoreSlim waitingReadLockSemaphore) private void ExitReadLock() { - lock (_writeLockLock) + lock (_writeLockSemaphore) { AssertNotDisposed(); if (_currentReaders == 0)