From 2a952a9885095affbae61cfb70cbba5a3b4974f2 Mon Sep 17 00:00:00 2001 From: Marius Thesing Date: Fri, 28 Aug 2026 17:43:16 +0200 Subject: [PATCH] make use of Lock type --- src/Npgsql/Internal/NpgsqlConnector.cs | 28 +++++++++---------- src/Npgsql/TypeMapping/GlobalTypeMapper.cs | 3 +- .../Util/ResettableCancellationTokenSource.cs | 2 +- .../SingleThreadSynchronizationContext.cs | 2 +- test/Npgsql.Tests/Support/TestBase.cs | 2 +- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/Npgsql/Internal/NpgsqlConnector.cs b/src/Npgsql/Internal/NpgsqlConnector.cs index cedcfeac8b..cbfbaff6c4 100644 --- a/src/Npgsql/Internal/NpgsqlConnector.cs +++ b/src/Npgsql/Internal/NpgsqlConnector.cs @@ -190,7 +190,7 @@ internal string InferredUserName /// cancellation is delivered. This reduces the chance that a cancellation meant for a previous /// command will accidentally cancel a later one, see #615. /// - object CancelLock { get; } = new(); + Lock CancelLock { get; } = new(); /// /// A lock that's taken to make sure no other concurrent operation is running. @@ -198,12 +198,12 @@ internal string InferredUserName /// Anyone else should immediately check the state and exit /// if the connector is closed. /// - object SyncObj { get; } = new(); + Lock SyncObj { get; } = new(); /// /// A lock that's used to wait for the Cleanup to complete while breaking the connection. /// - object CleanupLock { get; } = new(); + Lock CleanupLock { get; } = new(); readonly bool _isKeepAliveEnabled; readonly Timer? _keepAliveTimer; @@ -1918,7 +1918,7 @@ internal void PerformImmediateUserCancellation() return; // The connector is still alive, take the CancelLock before exiting SingleUseLock. // If a break will happen after, it's going to wait for the cancellation to complete. - Monitor.Enter(CancelLock); + CancelLock.Enter(); } try @@ -1939,7 +1939,7 @@ internal void PerformImmediateUserCancellation() } finally { - Monitor.Exit(CancelLock); + CancelLock.Exit(); } } @@ -1954,7 +1954,7 @@ void PerformDelayedUserCancellation() return; // The connector is still alive, take the CancelLock before exiting SingleUseLock. // If a break will happen after, it's going to wait for the cancellation to complete. - Monitor.Enter(CancelLock); + CancelLock.Enter(); } try @@ -1963,7 +1963,7 @@ void PerformDelayedUserCancellation() } finally { - Monitor.Exit(CancelLock); + CancelLock.Exit(); } } @@ -2265,14 +2265,14 @@ internal Exception Break(Exception reason, bool markHostAsOfflineOnConnecting = { Debug.Assert(!IsClosed); - Monitor.Enter(SyncObj); + SyncObj.Enter(); var state = State; if (state == ConnectorState.Broken) { // We're already broken. // Exit SingleUseLock to unblock other threads (like cancellation). - Monitor.Exit(SyncObj); + SyncObj.Exit(); // Wait for the break to complete before going forward. lock (CleanupLock) { } return reason; @@ -2287,12 +2287,12 @@ internal Exception Break(Exception reason, bool markHostAsOfflineOnConnecting = Interlocked.CompareExchange(ref _breakReason, reason, null); State = ConnectorState.Broken; // Take the CleanupLock while in SingleUseLock to make sure concurrent Break doesn't take it first. - Monitor.Enter(CleanupLock); + CleanupLock.Enter(); } finally { // Unblock other threads (like cancellation) to proceed and exit gracefully. - Monitor.Exit(SyncObj); + SyncObj.Exit(); } try @@ -2343,7 +2343,7 @@ internal Exception Break(Exception reason, bool markHostAsOfflineOnConnecting = } finally { - Monitor.Exit(CleanupLock); + CleanupLock.Exit(); } } @@ -2801,7 +2801,7 @@ internal void EndUserAction() void PerformKeepAlive(object? state) { Debug.Assert(_isKeepAliveEnabled); - if (!Monitor.TryEnter(SyncObj)) + if (!SyncObj.TryEnter()) return; try @@ -2833,7 +2833,7 @@ void PerformKeepAlive(object? state) } finally { - Monitor.Exit(SyncObj); + SyncObj.Exit(); } } diff --git a/src/Npgsql/TypeMapping/GlobalTypeMapper.cs b/src/Npgsql/TypeMapping/GlobalTypeMapper.cs index b5b8d0f904..ceb5a16a14 100644 --- a/src/Npgsql/TypeMapping/GlobalTypeMapper.cs +++ b/src/Npgsql/TypeMapping/GlobalTypeMapper.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Text.Json; +using System.Threading; using Npgsql.Internal; using Npgsql.Internal.Postgres; using Npgsql.Internal.ResolverFactories; @@ -13,7 +14,7 @@ sealed class GlobalTypeMapper : INpgsqlTypeMapper { readonly UserTypeMapper _userTypeMapper = new(); readonly List _pluginResolverFactories = []; - readonly object _sync = new(); + readonly Lock _sync = new(); PgTypeInfoResolverFactory[] _typeMappingResolvers = []; internal IEnumerable GetPluginResolverFactories() diff --git a/src/Npgsql/Util/ResettableCancellationTokenSource.cs b/src/Npgsql/Util/ResettableCancellationTokenSource.cs index 3218a7e629..b7e3fb39d0 100644 --- a/src/Npgsql/Util/ResettableCancellationTokenSource.cs +++ b/src/Npgsql/Util/ResettableCancellationTokenSource.cs @@ -25,7 +25,7 @@ sealed class ResettableCancellationTokenSource(TimeSpan timeout) : IDisposable /// /// Used, so we wouldn't concurrently use the cts for the cancellation, while it's being disposed /// - readonly object lockObject = new(); + readonly Lock lockObject = new(); #if DEBUG bool _isRunning; diff --git a/test/Npgsql.Tests/Support/SingleThreadSynchronizationContext.cs b/test/Npgsql.Tests/Support/SingleThreadSynchronizationContext.cs index a7fedad3d6..cdef857207 100644 --- a/test/Npgsql.Tests/Support/SingleThreadSynchronizationContext.cs +++ b/test/Npgsql.Tests/Support/SingleThreadSynchronizationContext.cs @@ -8,7 +8,7 @@ namespace Npgsql.Tests.Support; sealed class SingleThreadSynchronizationContext : SynchronizationContext, IDisposable { readonly BlockingCollection _tasks = new(); - readonly object _lockObject = new(); + readonly Lock _lockObject = new(); volatile Thread? _thread; bool _doingWork; diff --git a/test/Npgsql.Tests/Support/TestBase.cs b/test/Npgsql.Tests/Support/TestBase.cs index bfbf562c75..ded0bada11 100644 --- a/test/Npgsql.Tests/Support/TestBase.cs +++ b/test/Npgsql.Tests/Support/TestBase.cs @@ -25,7 +25,7 @@ public abstract class TestBase static readonly SemaphoreSlim DatabaseCreationLock = new(1); - static readonly object dataSourceLockObject = new(); + static readonly Lock dataSourceLockObject = new(); static ConcurrentDictionary DataSources = new(StringComparer.Ordinal);