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..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 @@ -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) - { + bool obtained = false; #if NETFRAMEWORK - RuntimeHelpers.PrepareConstrainedRegions(); + RuntimeHelpers.PrepareConstrainedRegions(); #endif - SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Creating new connection.", Id); - obj = UserCreateRequest(owningObject, userOptions); + 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); + } + } } } }