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);
+ }
+ }
}
}
}