@@ -362,7 +362,42 @@ internal WaitHandle[] GetHandles(bool withCreate)
362362 }
363363 }
364364
365- private const int MAX_Q_SIZE = ( int ) 0x00100000 ;
365+ /// <summary>
366+ /// Helper class to obtain and release a semaphore.
367+ /// </summary>
368+ internal class SemaphoreHolder : IDisposable
369+ {
370+ private readonly Semaphore _semaphore ;
371+
372+ /// <summary>
373+ /// Whether the semaphore was successfully obtained within the timeout.
374+ /// </summary>
375+ internal bool Obtained { get ; private set ; }
376+
377+ /// <summary>
378+ /// Obtains the semaphore, waiting up to the specified timeout.
379+ /// </summary>
380+ /// <param name="semaphore"></param>
381+ /// <param name="timeout"></param>
382+ internal SemaphoreHolder ( Semaphore semaphore , int timeout )
383+ {
384+ _semaphore = semaphore ;
385+ Obtained = _semaphore . WaitOne ( timeout ) ;
386+ }
387+
388+ /// <summary>
389+ /// Releases the semaphore if it was successfully obtained.
390+ /// </summary>
391+ public void Dispose ( )
392+ {
393+ if ( Obtained )
394+ {
395+ _semaphore . Release ( 1 ) ;
396+ }
397+ }
398+ }
399+
400+ private const int MAX_Q_SIZE = 0x00100000 ;
366401
367402 // The order of these is important; we want the WaitAny call to be signaled
368403 // for a free object before a creation signal. Only the index first signaled
@@ -1414,20 +1449,14 @@ private bool TryGetConnection(DbConnection owningObject, uint waitForMultipleObj
14141449
14151450 if ( onlyOneCheckConnection )
14161451 {
1417- if ( _waitHandles . CreationSemaphore . WaitOne ( unchecked ( ( int ) waitForMultipleObjectsTimeout ) ) )
1452+ using SemaphoreHolder semaphoreHolder = new ( _waitHandles . CreationSemaphore , unchecked ( ( int ) waitForMultipleObjectsTimeout ) ) ;
1453+ if ( semaphoreHolder . Obtained )
14181454 {
14191455#if NETFRAMEWORK
14201456 RuntimeHelpers . PrepareConstrainedRegions ( ) ;
14211457#endif
1422- try
1423- {
1424- SqlClientEventSource . Log . TryPoolerTraceEvent ( "<prov.DbConnectionPool.GetConnection|RES|CPOOL> {0}, Creating new connection." , ObjectID ) ;
1425- obj = UserCreateRequest ( owningObject , userOptions ) ;
1426- }
1427- finally
1428- {
1429- _waitHandles . CreationSemaphore . Release ( 1 ) ;
1430- }
1458+ SqlClientEventSource . Log . TryPoolerTraceEvent ( "<prov.DbConnectionPool.GetConnection|RES|CPOOL> {0}, Creating new connection." , ObjectID ) ;
1459+ obj = UserCreateRequest ( owningObject , userOptions ) ;
14311460 }
14321461 else
14331462 {
@@ -1657,26 +1686,20 @@ private void PoolCreateRequest(object state)
16571686 {
16581687 return ;
16591688 }
1660- int waitResult = BOGUS_HANDLE ;
16611689
16621690#if NETFRAMEWORK
16631691 RuntimeHelpers . PrepareConstrainedRegions ( ) ;
16641692#endif
16651693 try
16661694 {
16671695 // Obtain creation mutex so we're the only one creating objects
1668- // and we must have the wait result
1696+ using SemaphoreHolder semaphoreHolder = new ( _waitHandles . CreationSemaphore , CreationTimeout ) ;
1697+
1698+ if ( semaphoreHolder . Obtained )
1699+ {
16691700#if NETFRAMEWORK
16701701 RuntimeHelpers . PrepareConstrainedRegions ( ) ;
16711702#endif
1672- try
1673- { }
1674- finally
1675- {
1676- waitResult = WaitHandle . WaitAny ( _waitHandles . GetHandles ( withCreate : true ) , CreationTimeout ) ;
1677- }
1678- if ( CREATION_HANDLE == waitResult )
1679- {
16801703 DbConnectionInternal newObj ;
16811704
16821705 // Check ErrorOccurred again after obtaining mutex
@@ -1710,17 +1733,12 @@ private void PoolCreateRequest(object state)
17101733 }
17111734 }
17121735 }
1713- else if ( WaitHandle . WaitTimeout == waitResult )
1736+ else
17141737 {
17151738 // do not wait forever and potential block this worker thread
17161739 // instead wait for a period of time and just requeue to try again
17171740 QueuePoolCreateRequest ( ) ;
17181741 }
1719- else
1720- {
1721- // trace waitResult and ignore the failure
1722- SqlClientEventSource . Log . TryPoolerTraceEvent ( "<prov.DbConnectionPool.PoolCreateRequest|RES|CPOOL> {0}, PoolCreateRequest called WaitForSingleObject failed {1}" , ObjectID , waitResult ) ;
1723- }
17241742 }
17251743 catch ( Exception e )
17261744 {
@@ -1732,15 +1750,7 @@ private void PoolCreateRequest(object state)
17321750 // Now that CreateObject can throw, we need to catch the exception and discard it.
17331751 // There is no further action we can take beyond tracing. The error will be
17341752 // thrown to the user the next time they request a connection.
1735- SqlClientEventSource . Log . TryPoolerTraceEvent ( "<prov.DbConnectionPool.PoolCreateRequest|RES|CPOOL> {0}, PoolCreateRequest called CreateConnection which threw an exception: {1}" , ObjectID , e ) ;
1736- }
1737- finally
1738- {
1739- if ( CREATION_HANDLE == waitResult )
1740- {
1741- // reuse waitResult and ignore its value
1742- _waitHandles . CreationSemaphore . Release ( 1 ) ;
1743- }
1753+ SqlClientEventSource . Log . TryPoolerTraceEvent ( "<prov.DbConnectionPool.PoolCreateRequest|RES|CPOOL> {0}, PoolCreateRequest called CreateConnection which threw an exception: {1}" , Id , e ) ;
17441754 }
17451755 }
17461756 }
0 commit comments