From aabb9066e006d24a4a23ce2cb6bec75958901a31 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Mon, 6 Oct 2025 12:56:48 -0700 Subject: [PATCH 1/2] Cleanup semaphore holder --- .../WaitHandleDbConnectionPool.cs | 86 +++++++------------ 1 file changed, 32 insertions(+), 54 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs index da2246d8aa..48c1f6b6d7 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs @@ -382,42 +382,6 @@ internal WaitHandle[] GetHandles(bool withCreate) return withCreate ? _handlesWithCreate : _handlesWithoutCreate; } } - - /// - /// Helper class to obtain and release a semaphore. - /// - internal class SemaphoreHolder : IDisposable - { - private readonly Semaphore _semaphore; - - /// - /// Whether the semaphore was successfully obtained within the timeout. - /// - internal bool Obtained { get; private set; } - - /// - /// Obtains the semaphore, waiting up to the specified timeout. - /// - /// - /// - internal SemaphoreHolder(Semaphore semaphore, int timeout) - { - _semaphore = semaphore; - Obtained = _semaphore.WaitOne(timeout); - } - - /// - /// Releases the semaphore if it was successfully obtained. - /// - public void Dispose() - { - if (Obtained) - { - _semaphore.Release(1); - } - } - } - private const int MAX_Q_SIZE = 0x00100000; // The order of these is important; we want the WaitAny call to be signaled @@ -1356,26 +1320,36 @@ private bool TryGetConnection(DbConnection owningObject, uint waitForMultipleObj if (onlyOneCheckConnection) { - using SemaphoreHolder semaphoreHolder = new(_waitHandles.CreationSemaphore, unchecked((int)waitForMultipleObjectsTimeout)); - if (semaphoreHolder.Obtained) - { #if NETFRAMEWORK - RuntimeHelpers.PrepareConstrainedRegions(); + RuntimeHelpers.PrepareConstrainedRegions(); #endif - SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Creating new connection.", Id); - obj = UserCreateRequest(owningObject, userOptions); + bool obtained = false; + try + { + obtained = _waitHandles.CreationSemaphore.WaitOne(unchecked((int)waitForMultipleObjectsTimeout)); + if (obtained) + { + SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Creating new connection.", Id); + obj = UserCreateRequest(owningObject, userOptions); + } + else + { + // Timeout waiting for creation semaphore - return null + SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Wait timed out.", Id); + connection = null; + return false; + } } - else + finally { - // Timeout waiting for creation semaphore - return null - SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Wait timed out.", Id); - connection = null; - return false; + if (obtained) + { + _waitHandles.CreationSemaphore.Release(1); + } } } } break; - case WAIT_ABANDONED + SEMAPHORE_HANDLE: SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Semaphore handle abandonded.", Id); Interlocked.Decrement(ref _waitCount); @@ -1582,20 +1556,17 @@ private void PoolCreateRequest(object state) { return; } - #if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); #endif + bool obtained = false; try { // Obtain creation mutex so we're the only one creating objects - using SemaphoreHolder semaphoreHolder = new(_waitHandles.CreationSemaphore, CreationTimeout); + obtained = _waitHandles.CreationSemaphore.WaitOne(CreationTimeout); - if (semaphoreHolder.Obtained) + if (obtained) { -#if NETFRAMEWORK - RuntimeHelpers.PrepareConstrainedRegions(); -#endif DbConnectionInternal newObj; // Check ErrorOccurred again after obtaining mutex @@ -1648,6 +1619,13 @@ private void PoolCreateRequest(object state) // thrown to the user the next time they request a connection. SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, PoolCreateRequest called CreateConnection which threw an exception: {1}", Id, e); } + finally + { + if (obtained) + { + _waitHandles.CreationSemaphore.Release(1); + } + } } } } From c744b4df79eebddcb2556d32aa715527650bfe90 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Mon, 6 Oct 2025 16:39:20 -0700 Subject: [PATCH 2/2] Minor change (fix cer) --- .../Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs index 48c1f6b6d7..387019910b 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs @@ -1320,10 +1320,10 @@ private bool TryGetConnection(DbConnection owningObject, uint waitForMultipleObj if (onlyOneCheckConnection) { + bool obtained = false; #if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); #endif - bool obtained = false; try { obtained = _waitHandles.CreationSemaphore.WaitOne(unchecked((int)waitForMultipleObjectsTimeout));