@@ -383,6 +383,41 @@ internal WaitHandle[] GetHandles(bool withCreate)
383383 }
384384 }
385385
386+ /// <summary>
387+ /// Helper class to obtain and release a semaphore.
388+ /// </summary>
389+ internal class SemaphoreHolder : IDisposable
390+ {
391+ private readonly Semaphore _semaphore ;
392+
393+ /// <summary>
394+ /// Whether the semaphore was successfully obtained within the timeout.
395+ /// </summary>
396+ internal bool Obtained { get ; private set ; }
397+
398+ /// <summary>
399+ /// Obtains the semaphore, waiting up to the specified timeout.
400+ /// </summary>
401+ /// <param name="semaphore"></param>
402+ /// <param name="timeout"></param>
403+ internal SemaphoreHolder ( Semaphore semaphore , int timeout )
404+ {
405+ _semaphore = semaphore ;
406+ Obtained = _semaphore . WaitOne ( timeout ) ;
407+ }
408+
409+ /// <summary>
410+ /// Releases the semaphore if it was successfully obtained.
411+ /// </summary>
412+ public void Dispose ( )
413+ {
414+ if ( Obtained )
415+ {
416+ _semaphore . Release ( 1 ) ;
417+ }
418+ }
419+ }
420+
386421 private const int MAX_Q_SIZE = 0x00100000 ;
387422
388423 // The order of these is important; we want the WaitAny call to be signaled
@@ -1321,20 +1356,14 @@ private bool TryGetConnection(DbConnection owningObject, uint waitForMultipleObj
13211356
13221357 if ( onlyOneCheckConnection )
13231358 {
1324- if ( _waitHandles . CreationSemaphore . WaitOne ( unchecked ( ( int ) waitForMultipleObjectsTimeout ) ) )
1359+ using SemaphoreHolder semaphoreHolder = new ( _waitHandles . CreationSemaphore , unchecked ( ( int ) waitForMultipleObjectsTimeout ) ) ;
1360+ if ( semaphoreHolder . Obtained )
13251361 {
13261362#if NETFRAMEWORK
13271363 RuntimeHelpers . PrepareConstrainedRegions ( ) ;
13281364#endif
1329- try
1330- {
1331- SqlClientEventSource . Log . TryPoolerTraceEvent ( "<prov.DbConnectionPool.GetConnection|RES|CPOOL> {0}, Creating new connection." , Id ) ;
1332- obj = UserCreateRequest ( owningObject , userOptions ) ;
1333- }
1334- finally
1335- {
1336- _waitHandles . CreationSemaphore . Release ( 1 ) ;
1337- }
1365+ SqlClientEventSource . Log . TryPoolerTraceEvent ( "<prov.DbConnectionPool.GetConnection|RES|CPOOL> {0}, Creating new connection." , Id ) ;
1366+ obj = UserCreateRequest ( owningObject , userOptions ) ;
13381367 }
13391368 else
13401369 {
@@ -1553,26 +1582,20 @@ private void PoolCreateRequest(object state)
15531582 {
15541583 return ;
15551584 }
1556- int waitResult = BOGUS_HANDLE ;
15571585
15581586#if NETFRAMEWORK
15591587 RuntimeHelpers . PrepareConstrainedRegions ( ) ;
15601588#endif
15611589 try
15621590 {
15631591 // Obtain creation mutex so we're the only one creating objects
1564- // and we must have the wait result
1592+ using SemaphoreHolder semaphoreHolder = new ( _waitHandles . CreationSemaphore , CreationTimeout ) ;
1593+
1594+ if ( semaphoreHolder . Obtained )
1595+ {
15651596#if NETFRAMEWORK
15661597 RuntimeHelpers . PrepareConstrainedRegions ( ) ;
15671598#endif
1568- try
1569- { }
1570- finally
1571- {
1572- waitResult = WaitHandle . WaitAny ( _waitHandles . GetHandles ( withCreate : true ) , CreationTimeout ) ;
1573- }
1574- if ( CREATION_HANDLE == waitResult )
1575- {
15761599 DbConnectionInternal newObj ;
15771600
15781601 // Check ErrorOccurred again after obtaining mutex
@@ -1606,17 +1629,12 @@ private void PoolCreateRequest(object state)
16061629 }
16071630 }
16081631 }
1609- else if ( WaitHandle . WaitTimeout == waitResult )
1632+ else
16101633 {
16111634 // do not wait forever and potential block this worker thread
16121635 // instead wait for a period of time and just requeue to try again
16131636 QueuePoolCreateRequest ( ) ;
16141637 }
1615- else
1616- {
1617- // trace waitResult and ignore the failure
1618- SqlClientEventSource . Log . TryPoolerTraceEvent ( "<prov.DbConnectionPool.PoolCreateRequest|RES|CPOOL> {0}, PoolCreateRequest called WaitForSingleObject failed {1}" , Id , waitResult ) ;
1619- }
16201638 }
16211639 catch ( Exception e )
16221640 {
@@ -1630,14 +1648,6 @@ private void PoolCreateRequest(object state)
16301648 // thrown to the user the next time they request a connection.
16311649 SqlClientEventSource . Log . TryPoolerTraceEvent ( "<prov.DbConnectionPool.PoolCreateRequest|RES|CPOOL> {0}, PoolCreateRequest called CreateConnection which threw an exception: {1}" , Id , e ) ;
16321650 }
1633- finally
1634- {
1635- if ( CREATION_HANDLE == waitResult )
1636- {
1637- // reuse waitResult and ignore its value
1638- _waitHandles . CreationSemaphore . Release ( 1 ) ;
1639- }
1640- }
16411651 }
16421652 }
16431653 }
0 commit comments