private bool TryGetConnection(DbConnection owningObject, uint waitForMultipleObjectsTimeout, bool allowCreate, bool onlyOneCheckConnection, DbConnectionOptions userOptions, out DbConnectionInternal connection) { DbConnectionInternal obj = null; if (null == obj) { Interlocked.Increment(ref _waitCount); do { int waitResult = BOGUS_HANDLE; try { try { } finally { waitResult = WaitHandle.WaitAny(_waitHandles.GetHandles(allowCreate), unchecked ((int)waitForMultipleObjectsTimeout)); } // From the WaitAny docs: "If more than one object became signaled during // the call, this is the array index of the signaled object with the // smallest index value of all the signaled objects." This is important // so that the free object signal will be returned before a creation // signal. switch (waitResult) { case WaitHandle.WaitTimeout: Interlocked.Decrement(ref _waitCount); connection = null; return(false); case ERROR_HANDLE: // Throw the error that PoolCreateRequest stashed. Interlocked.Decrement(ref _waitCount); throw TryCloneCachedException(); case CREATION_HANDLE: try { obj = UserCreateRequest(owningObject, userOptions); } catch { if (null == obj) { Interlocked.Decrement(ref _waitCount); } throw; } finally { // Ensure that we release this waiter, regardless // of any exceptions that may be thrown. if (null != obj) { Interlocked.Decrement(ref _waitCount); } } if (null == obj) { // If we were not able to create an object, check to see if // we reached MaxPoolSize. If so, we will no longer wait on // the CreationHandle, but instead wait for a free object or // the timeout. if (Count >= MaxPoolSize && 0 != MaxPoolSize) { if (!ReclaimEmancipatedObjects()) { // modify handle array not to wait on creation mutex anymore Debug.Assert(2 == CREATION_HANDLE, "creation handle changed value"); allowCreate = false; } } } break; case SEMAPHORE_HANDLE: // // guaranteed available inventory // Interlocked.Decrement(ref _waitCount); obj = GetFromGeneralPool(); if ((obj != null) && (!obj.IsConnectionAlive())) { DestroyObject(obj); obj = null; // Setting to null in case creating a new object fails if (onlyOneCheckConnection) { if (_waitHandles.CreationSemaphore.WaitOne(unchecked ((int)waitForMultipleObjectsTimeout))) { try { obj = UserCreateRequest(owningObject, userOptions); } finally { _waitHandles.CreationSemaphore.Release(1); } } else { // Timeout waiting for creation semaphore - return null connection = null; return(false); } } } break; default: Interlocked.Decrement(ref _waitCount); throw ADP.InternalError(ADP.InternalErrorCode.UnexpectedWaitAnyResult); } } finally { if (CREATION_HANDLE == waitResult) { _waitHandles.CreationSemaphore.Release(1); } } } while (null == obj); } if (null != obj) { PrepareConnection(owningObject, obj); } connection = obj; return(true); }
private bool TryGetConnection(DbConnection owningObject, int waitForMultipleObjectsTimeout, bool allowCreate, bool onlyOneCheckConnection, DbConnectionOptions userOptions, out DbConnectionInternal connection) { DbConnectionInternal obj = null; if (null == obj) { Interlocked.Increment(ref _waitCount); do { int waitResult = WaitHandle.WaitTimeout; try { if (!allowCreate) { if (_waitHandles.PoolSemaphore.Wait(waitForMultipleObjectsTimeout)) { waitResult = SEMAPHORE_HANDLE; } else { waitResult = WaitHandle.WaitTimeout; } } else { bool obtainedPoolSemaphore = false; DateTime start = DateTime.UtcNow; do { waitResult = WaitHandle.WaitAny(_waitHandles.Handles, waitForMultipleObjectsTimeout); // Obtaining the WaitHandle for a SemaphoreSlim doesn't actually take one from the count // So we need to wait on the SemaphoreSlim seperately if (waitResult == SEMAPHORE_HANDLE) { if (_waitHandles.PoolSemaphore.Wait(TimeSpan.Zero)) { obtainedPoolSemaphore = true; } else { DateTime currentTime = DateTime.UtcNow; waitForMultipleObjectsTimeout -= (currentTime - start).Milliseconds; } } } while ((waitResult == SEMAPHORE_HANDLE) && !obtainedPoolSemaphore); } // From the WaitAny docs: "If more than one object became signaled during // the call, this is the array index of the signaled object with the // smallest index value of all the signaled objects." This is important // so that the free object signal will be returned before a creation // signal. switch (waitResult) { case WaitHandle.WaitTimeout: Interlocked.Decrement(ref _waitCount); connection = null; return(false); case CREATION_HANDLE: try { obj = UserCreateRequest(owningObject, userOptions); } catch { if (null == obj) { Interlocked.Decrement(ref _waitCount); } throw; } finally { // Ensure that we release this waiter, regardless // of any exceptions that may be thrown. if (null != obj) { Interlocked.Decrement(ref _waitCount); } } if (null == obj) { // If we were not able to create an object, check to see if // we reached MaxPoolSize. If so, we will no longer wait on // the CreationHandle, but instead wait for a free object or // the timeout. if (Count >= MaxPoolSize && 0 != MaxPoolSize) { if (!ReclaimEmancipatedObjects()) { // modify handle array not to wait on creation mutex anymore allowCreate = false; } } } break; case SEMAPHORE_HANDLE: // // guaranteed available inventory // Interlocked.Decrement(ref _waitCount); obj = GetFromGeneralPool(); if ((obj != null) && (!obj.IsConnectionAlive())) { DestroyObject(obj); obj = null; // Setting to null in case creating a new object fails if (onlyOneCheckConnection) { if (_waitHandles.CreationSemaphore.WaitOne(unchecked ((int)waitForMultipleObjectsTimeout))) { try { obj = UserCreateRequest(owningObject, userOptions); } finally { _waitHandles.CreationSemaphore.Release(1); } } else { // Timeout waiting for creation semaphore - return null connection = null; return(false); } } } break; default: Interlocked.Decrement(ref _waitCount); throw ADP.InternalError(ADP.InternalErrorCode.UnexpectedWaitAnyResult); } } finally { if (CREATION_HANDLE == waitResult) { _waitHandles.CreationSemaphore.Release(); } } } while (null == obj); } if (null != obj) { PrepareConnection(owningObject, obj); } connection = obj; return(true); }