DbConnectionPool.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / Data / System / Data / ProviderBase / DbConnectionPool.cs / 1 / DbConnectionPool.cs

                            //------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
namespace System.Data.ProviderBase { 

    using System; 
    using System.Collections;
    using System.Collections.Generic;
    using System.Data.Common;
    using System.Diagnostics; 
    using System.Globalization;
    using System.Runtime.CompilerServices; 
    using System.Runtime.ConstrainedExecution; 
    using System.Runtime.InteropServices;
    using System.Security; 
    using System.Security.Permissions;
    using System.Security.Principal;
    using System.Threading;
    using SysTx = System.Transactions; 

    sealed internal class DbConnectionPool { 
        private enum State { 
            Initializing,
            Running, 
            ShuttingDown,
        }

        internal const Bid.ApiGroup PoolerTracePoints = (Bid.ApiGroup)0x1000; 

        // Hotfix: SQLBUVSTS01 # 272199: Hotfix request for RFC #50003517 
        // [PS SQL Hotfix RFC # 50003517: Current Transaction is disposed within the transaction scope, 
        //      before leaving TransactionScope block against SQL Server 2008]
        // This class is a way to stash our cloned Tx key for later disposal when it's no longer needed. 
        // We can't get at the key in the dictionary without enumerating entries, so we stash an extra
        // copy as part of the value.
        sealed private class TransactedConnectionList : List {
            private SysTx.Transaction _transaction; 
            internal TransactedConnectionList(int initialAllocation, SysTx.Transaction tx) : base(initialAllocation) {
                _transaction = tx; 
            } 

            internal void Dispose() { 
                if (null != _transaction) {
                    _transaction.Dispose();
                }
            } 
        }
 
        sealed private class TransactedConnectionPool : Dictionary { 
            DbConnectionPool _pool;
 
            private static int _objectTypeCount; // Bid counter
            internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);

            internal TransactedConnectionPool(DbConnectionPool pool) : base() { 
                Debug.Assert(null != pool, "null pool?");
 
                _pool = pool; 
                Bid.PoolerTrace(" %d#, Constructed for connection pool %d#\n", ObjectID, _pool.ObjectID);
            } 

            internal int ObjectID {
                get {
                    return _objectID; 
                }
            } 
 
            internal DbConnectionPool Pool {
                get { 
                    return _pool;
                }
            }
 
            internal DbConnectionInternal GetTransactedObject(SysTx.Transaction transaction) {
                Debug.Assert(null != transaction, "null transaction?"); 
 
                DbConnectionInternal transactedObject = null;
 
                TransactedConnectionList connections;

                if (this.TryGetValue(transaction, out connections)) {
                    lock (connections) { 
                        int i = connections.Count - 1;
                        if (0 <= i) { 
                            transactedObject = connections[i]; 
                            connections.RemoveAt(i);
                        } 
                    }
                }

                if (null != transactedObject) { 
                    Bid.PoolerTrace(" %d#, Transaction %d#, Connection %d#, Popped.\n", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID);
                } 
                return transactedObject; 
            }
 
            internal void PutTransactedObject(SysTx.Transaction transaction, DbConnectionInternal transactedObject) {
                Debug.Assert(null != transaction, "null transaction?");
                Debug.Assert(null != transactedObject, "null transactedObject?");
 
                Bid.PoolerTrace(" %d#, Transaction %d#, Connection %d#, Pushing.\n", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID);
 
                TransactedConnectionList connections; 

                // NOTE: it is possible that the connecton was put on the 
                //       deactivate queue, and while it was on the queue, the
                //       transaction ended, causing the list for the transaction
                //       to have been removed.  In that case, we can't expect
                //       the list to be here. 
                if (this.TryGetValue(transaction, out connections)) {
                    lock (connections) { 
                        Debug.Assert(0 > connections.IndexOf(transactedObject), "adding to pool a second time?"); 
                        connections.Add(transactedObject);
                        Pool.PerformanceCounters.NumberOfFreeConnections.Increment(); 
                    }
                }
            }
 
            internal void TransactionBegin(SysTx.Transaction transaction) {
                Bid.PoolerTrace(" %d#, Transaction %d#, Begin.\n", ObjectID, transaction.GetHashCode()); 
 
                TransactedConnectionList connections;
 
                if (!this.TryGetValue(transaction, out connections)) {
                    SysTx.Transaction transactionClone = null;
                    try {
                        transactionClone = transaction.Clone(); 
                        TransactedConnectionList newConnections = new TransactedConnectionList(2, transactionClone); // start with only two connections in the list; most times we won't need that many.
 
                        Bid.PoolerTrace(" %d#, Transaction %d#, Adding List to transacted pool.\n", ObjectID, transaction.GetHashCode()); 
                        lock (this) {
                            if (!this.TryGetValue(transaction, out connections)) { 
                                connections = newConnections;
                                this.Add(transactionClone, connections);
                                transactionClone = null; // we've used it -- don't throw it away.
                            } 
                        }
                    } 
                    finally { 
                        if (null != transactionClone) {
                            transactionClone.Dispose(); 
                        }
                    }
                    Bid.PoolerTrace(" %d#, Transaction %d#, Added.\n", ObjectID, transaction.GetHashCode());
                } 
            }
 
            internal void TransactionEnded(SysTx.Transaction transaction, DbConnectionInternal transactedObject) { 
                Bid.PoolerTrace(" %d#, Transaction %d#, Connection %d#, Transaction Completed\n", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID);
 
                TransactedConnectionList connections;
                int entry = -1;

                // NOTE: we may be ending a transaction for a connection that is 
                //       currently not in the pool, and therefore it may not have
                //       a list for it, because it may have been removed already. 
                if (this.TryGetValue(transaction, out connections)) { 
                    lock (connections) {
                        entry = connections.IndexOf(transactedObject); 

                        if (entry >= 0) {
                            connections.RemoveAt(entry);
                        } 

                        // Once we've completed all the ended notifications, we can 
                        // safely remove the list from the transacted pool. 
                        if (0 >= connections.Count) {
                            Bid.PoolerTrace(" %d#, Transaction %d#, Removing List from transacted pool.\n", ObjectID, transaction.GetHashCode()); 
                            lock (this) {
                                Remove(transaction);
                            }
                            Bid.PoolerTrace(" %d#, Transaction %d#, Removed.\n", ObjectID, transaction.GetHashCode()); 

                            // we really need to dispose our connection list; it may have 
                            // native resources via the tx and GC may not happen soon enough. 
                            connections.Dispose();
                        } 
                    }
                }

                // If (and only if) we found the connection in the list of 
                // connections, we'll put it back...
                if (0 <= entry)  { 
                    Pool.PerformanceCounters.NumberOfFreeConnections.Decrement(); 
                    Pool.PutObjectFromTransactedPool(transactedObject);
                } 
            }
        }

        private sealed class PoolWaitHandles : DbBuffer { 

            private readonly Semaphore _poolSemaphore; 
            private readonly ManualResetEvent _errorEvent; 

            // Using a Mutex requires ThreadAffinity because SQL CLR can swap 
            // the underlying Win32 thread associated with a managed thread in preemptive mode.
            // Using an AutoResetEvent does not have that complication.
            private readonly Semaphore _creationSemaphore;
 
            private readonly SafeHandle _poolHandle;
            private readonly SafeHandle _errorHandle; 
            private readonly SafeHandle _creationHandle; 

            private readonly int _releaseFlags; 

            internal PoolWaitHandles(Semaphore poolSemaphore, ManualResetEvent errorEvent, Semaphore creationSemaphore) : base(3*IntPtr.Size) {
                bool mustRelease1 = false, mustRelease2 = false, mustRelease3 = false;
                RuntimeHelpers.PrepareConstrainedRegions(); 
                try {
                    _poolSemaphore     = poolSemaphore; 
                    _errorEvent        = errorEvent; 
                    _creationSemaphore = creationSemaphore;
 
                    // because SafeWaitHandle doesn't have reliability contract
                    _poolHandle     = poolSemaphore.SafeWaitHandle;
                    _errorHandle    = errorEvent.SafeWaitHandle;
                    _creationHandle = creationSemaphore.SafeWaitHandle; 

                    _poolHandle.DangerousAddRef(ref mustRelease1); 
                    _errorHandle.DangerousAddRef(ref mustRelease2); 
                    _creationHandle.DangerousAddRef(ref mustRelease3);
 
                    Debug.Assert(0 == SEMAPHORE_HANDLE, "SEMAPHORE_HANDLE");
                    Debug.Assert(1 == ERROR_HANDLE, "ERROR_HANDLE");
                    Debug.Assert(2 == CREATION_HANDLE, "CREATION_HANDLE");
 
                    WriteIntPtr(SEMAPHORE_HANDLE*IntPtr.Size, _poolHandle.DangerousGetHandle());
                    WriteIntPtr(ERROR_HANDLE*IntPtr.Size,     _errorHandle.DangerousGetHandle()); 
                    WriteIntPtr(CREATION_HANDLE*IntPtr.Size,  _creationHandle.DangerousGetHandle()); 
                }
                finally { 
                    if (mustRelease1) {
                        _releaseFlags |= 1;
                    }
                    if (mustRelease2) { 
                        _releaseFlags |= 2;
                    } 
                    if (mustRelease3) { 
                        _releaseFlags |= 4;
                    } 
                }
            }

            internal SafeHandle CreationHandle { 
                [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
                get { return _creationHandle; } 
            } 

            internal Semaphore CreationSemaphore { 
                get { return _creationSemaphore; }
            }

            internal ManualResetEvent ErrorEvent { 
                get { return _errorEvent; }
            } 
 
            internal Semaphore PoolSemaphore {
                get { return _poolSemaphore; } 
            }

            protected override bool ReleaseHandle() {
                // NOTE: The SafeHandle class guarantees this will be called exactly once. 
                // we know we can touch these other managed objects because of our original DangerousAddRef
                if (0 != (1 & _releaseFlags)) { 
                    _poolHandle.DangerousRelease(); 
                }
                if (0 != (2 & _releaseFlags)) { 
                    _errorHandle.DangerousRelease();
                }
                if (0 != (4 & _releaseFlags)) {
                    _creationHandle.DangerousRelease(); 
                }
                return base.ReleaseHandle(); 
            } 
        }
 
        private const int MAX_Q_SIZE    = (int)0x00100000;

        // The order of these is important; we want the WaitAny call to be signaled
        // for a free object before a creation signal.  Only the index first signaled 
        // object is returned from the WaitAny call.
        private const int SEMAPHORE_HANDLE = (int)0x0; 
        private const int ERROR_HANDLE     = (int)0x1; 
        private const int CREATION_HANDLE  = (int)0x2;
        private const int BOGUS_HANDLE     = (int)0x3; 

        private const int WAIT_OBJECT_0 = 0;
        private const int WAIT_TIMEOUT   = (int)0x102;
        private const int WAIT_ABANDONED = (int)0x80; 
        private const int WAIT_FAILED    = -1;
 
        private const int ERROR_WAIT_DEFAULT = 5 * 1000; // 5 seconds 

        // we do want a testable, repeatable set of generated random numbers 
        private static readonly Random _random = new Random(5101977); // Value obtained from Dave Driver

        private readonly int              _cleanupWait;
        private readonly DbConnectionPoolIdentity _identity; 

        private readonly DbConnectionFactory          _connectionFactory; 
        private readonly DbConnectionPoolGroup        _connectionPoolGroup; 
        private readonly DbConnectionPoolGroupOptions _connectionPoolGroupOptions;
        private          DbConnectionPoolProviderInfo _connectionPoolProviderInfo; 

        private State                     _state;

        private readonly DbConnectionInternalListStack _stackOld = new DbConnectionInternalListStack(); 
        private readonly DbConnectionInternalListStack _stackNew = new DbConnectionInternalListStack();
 
        private readonly WaitCallback     _poolCreateRequest; 

        private readonly Queue            _deactivateQueue; 
        private readonly WaitCallback     _deactivateCallback;

        private int                       _waitCount;
        private readonly PoolWaitHandles  _waitHandles; 

        private Exception                 _resError; 
        private volatile bool             _errorOccurred; 

        private int                       _errorWait; 
        private Timer                     _errorTimer;

        private Timer                     _cleanupTimer;
 
        private readonly TransactedConnectionPool _transactedConnectionPool;
 
        private readonly List _objectList; 
        private int                       _totalObjects;
 
        private static int _objectTypeCount; // Bid counter
        internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);

        // only created by DbConnectionPoolGroup.GetConnectionPool 
        internal DbConnectionPool(
                            DbConnectionFactory connectionFactory, 
                            DbConnectionPoolGroup connectionPoolGroup, 
                            DbConnectionPoolIdentity identity,
                            DbConnectionPoolProviderInfo connectionPoolProviderInfo ) { 
            Debug.Assert(ADP.IsWindowsNT, "Attempting to construct a connection pool on Win9x?");
            Debug.Assert(null != connectionPoolGroup, "null connectionPoolGroup");

            if ((null != identity) && identity.IsRestricted) { 
                throw ADP.InternalError(ADP.InternalErrorCode.AttemptingToPoolOnRestrictedToken);
            } 
 
            _state= State.Initializing;
 
            lock(_random) { // Random.Next is not thread-safe
                _cleanupWait = _random.Next(12, 24)*10*1000; // 2-4 minutes in 10 sec intervals, WebData 103603
            }
 
            _connectionFactory = connectionFactory;
            _connectionPoolGroup = connectionPoolGroup; 
            _connectionPoolGroupOptions = connectionPoolGroup.PoolGroupOptions; 
            _connectionPoolProviderInfo = connectionPoolProviderInfo;
            _identity = identity; 

            if (UseDeactivateQueue) {
                _deactivateQueue = new Queue();
                _deactivateCallback = new WaitCallback(ProcessDeactivateQueue); 
            }
 
            _waitHandles = new PoolWaitHandles( 
                                new Semaphore(0, MAX_Q_SIZE),
                                new ManualResetEvent(false), 
                                new Semaphore(1, 1));

            _errorWait      = ERROR_WAIT_DEFAULT;
            _errorTimer     = null;  // No error yet. 

            _objectList     = new List(MaxPoolSize); 
 
            if(ADP.IsPlatformNT5) {
                _transactedConnectionPool = new TransactedConnectionPool(this); 
            }

            _poolCreateRequest = new WaitCallback(PoolCreateRequest); // used by CleanupCallback
            _state = State.Running; 

            Bid.PoolerTrace(" %d#, Constructed.\n", ObjectID); 
 
            //_cleanupTimer & QueuePoolCreateRequest is delayed until DbConnectionPoolGroup calls
            // StartBackgroundCallbacks after pool is actually in the collection 
        }

        private int CreationTimeout {
            get { return PoolGroupOptions.CreationTimeout; } 
        }
 
        internal int Count { 
            get { return _totalObjects; }
        } 

        internal DbConnectionFactory ConnectionFactory {
            get { return _connectionFactory; }
        } 

        internal bool ErrorOccurred { 
            get { return _errorOccurred; } 
        }
 
        private bool HasTransactionAffinity {
            get { return PoolGroupOptions.HasTransactionAffinity; }
        }
 
        internal TimeSpan LoadBalanceTimeout {
            get { return PoolGroupOptions.LoadBalanceTimeout; } 
        } 

        private bool NeedToReplenish { 
            get {
                if (State.Running != _state) // SQL BU DT 364595 - don't allow connection create when not running.
                    return false;
 
                int totalObjects = Count;
 
                if (totalObjects >= MaxPoolSize) 
                    return false;
 
                if (totalObjects < MinPoolSize)
                    return true;

                int freeObjects        = (_stackNew.Count + _stackOld.Count); 
                int waitingRequests    = _waitCount;
                bool needToReplenish = (freeObjects < waitingRequests) || ((freeObjects == waitingRequests) && (totalObjects > 1)); 
 
                return needToReplenish;
            } 
        }

        internal DbConnectionPoolIdentity Identity {
            get { return _identity; } 
        }
 
        internal bool IsRunning { 
            get { return State.Running == _state; }
        } 

        private int MaxPoolSize {
            get { return PoolGroupOptions.MaxPoolSize; }
        } 

        private int MinPoolSize { 
            get { return PoolGroupOptions.MinPoolSize; } 
        }
 
        internal int ObjectID {
            get {
                return _objectID;
            } 
        }
 
        internal DbConnectionPoolCounters PerformanceCounters { 
            get { return _connectionFactory.PerformanceCounters; }
        } 

        internal DbConnectionPoolGroup PoolGroup {
            get { return _connectionPoolGroup; }
        } 

        internal DbConnectionPoolGroupOptions PoolGroupOptions { 
            get { return _connectionPoolGroupOptions; } 
        }
 
        internal DbConnectionPoolProviderInfo ProviderInfo {
            get { return _connectionPoolProviderInfo; }
        }
 
        private bool UseDeactivateQueue {
            get { return PoolGroupOptions.UseDeactivateQueue; } 
        } 

        internal bool UseLoadBalancing { 
            get { return PoolGroupOptions.UseLoadBalancing; }
        }

        private bool UsingIntegrateSecurity { 
            get { return (null != _identity && DbConnectionPoolIdentity.NoIdentity != _identity); }
        } 
 
        private void CleanupCallback(Object state) {
            // Called when the cleanup-timer ticks over. 

            // This is the automatic prunning method.  Every period, we will
            // perform a two-step process:
            // 
            // First, for each free object above MinPoolSize, we will obtain a
            // semaphore representing one object and destroy one from old stack. 
            // We will continue this until we either reach MinPoolSize, we are 
            // unable to obtain a free object, or we have exhausted all the
            // objects on the old stack. 
            //
            // Second we move all free objects on the new stack to the old stack.
            // So, every period the objects on the old stack are destroyed and
            // the objects on the new stack are pushed to the old stack.  All 
            // objects that are currently out and in use are not on either stack.
            // 
            // With this logic, objects are pruned from the pool if unused for 
            // at least one period but not more than two periods.
 
            Bid.PoolerTrace(" %d#\n", ObjectID);

            // Destroy free objects that put us above MinPoolSize from old stack.
            while(Count > MinPoolSize) { // While above MinPoolSize... 

                if (_waitHandles.PoolSemaphore.WaitOne(0, false) /* != WAIT_TIMEOUT */) { 
                    // We obtained a objects from the semaphore. 
                    DbConnectionInternal obj = _stackOld.SynchronizedPop();
 
                    if (null != obj) {
                        // If we obtained one from the old stack, destroy it.
                        PerformanceCounters.NumberOfFreeConnections.Decrement();
 
                        // Transaction roots must survive even aging out (TxEnd event will clean them up).
                        bool shouldDestroy = true; 
                        lock (obj) {    // Lock to prevent ---- window between IsTransactionRoot and shouldDestroy assignment 
                            if (obj.IsTransactionRoot) {
                                shouldDestroy = false; 
                            }
                        }

                        // !!!!!!!!!! WARNING !!!!!!!!!!!!! 
                        //   ONLY touch obj after lock release if shouldDestroy is false!!!  Otherwise, it may be destroyed
                        //   by transaction-end thread! 
 
                        // Note that there is a minor race condition between this task and the transaction end event, if the latter runs
                        //  between the lock above and the SetInStasis call below. The reslult is that the stasis counter may be 
                        //  incremented without a corresponding decrement (the transaction end task is normally expected
                        //  to decrement, but will only do so if the stasis flag is set when it runs). I've minimized the size
                        //  of the window, but we aren't totally eliminating it due to SetInStasis needing to do bid tracing, which
                        //  we don't want to do under this lock, if possible. It should be possible to eliminate this ---- with 
                        //  more substantial re-architecture of the pool, but we don't have the time to do that work for the current release.
 
                        if (shouldDestroy) { 
                            DestroyObject(obj);
                        } 
                        else {
                            obj.SetInStasis();
                        }
                    } 
                    else {
                        // Else we exhausted the old stack (the object the 
                        // semaphore represents is on the new stack), so break. 
                        _waitHandles.PoolSemaphore.Release(1);
                        break; 
                    }
                }
                else {
                    break; 
                }
            } 
 
            // Push to the old-stack.  For each free object, move object from
            // new stack to old stack. 
            if(_waitHandles.PoolSemaphore.WaitOne(0, false) /* != WAIT_TIMEOUT */) {
                for(;;) {
                    DbConnectionInternal obj = _stackNew.SynchronizedPop();
 
                    if (null == obj)
                        break; 
 
                    Bid.PoolerTrace(" %d#, ChangeStacks=%d#\n", ObjectID, obj.ObjectID);
 
                    Debug.Assert(!obj.IsEmancipated, "pooled object not in pool");
                    Debug.Assert(obj.CanBePooled,     "pooled object is not poolable");

                    _stackOld.SynchronizedPush(obj); 
                }
                _waitHandles.PoolSemaphore.Release(1); 
            } 

            // Queue up a request to bring us up to MinPoolSize 
            QueuePoolCreateRequest();
        }

        internal void Clear() { 
            Bid.PoolerTrace(" %d#, Clearing.\n", ObjectID);
 
            DbConnectionInternal obj; 

            // First, quickly doom everything. 
            lock(_objectList) {
                int count = _objectList.Count;

                for (int i = 0; i < count; ++i) { 
                    obj = _objectList[i];
 
                    if (null != obj) { 
                        obj.DoNotPoolThisConnection();
                    } 
                }
            }

            // Second, dispose of all the free connections. 
            while (null != (obj = _stackNew.SynchronizedPop())) {
                PerformanceCounters.NumberOfFreeConnections.Decrement(); 
                DestroyObject(obj); 
            }
            while (null != (obj = _stackOld.SynchronizedPop())) { 
                PerformanceCounters.NumberOfFreeConnections.Decrement();
                DestroyObject(obj);
            }
 
            // Finally, reclaim everything that's emancipated (which, because
            // it's been doomed, will cause it to be disposed of as well) 
            ReclaimEmancipatedObjects(); 

            Bid.PoolerTrace(" %d#, Cleared.\n", ObjectID); 
        }

        private Timer CreateCleanupTimer() {
            return (new Timer(new TimerCallback(this.CleanupCallback), null, _cleanupWait, _cleanupWait)); 
        }
 
        private DbConnectionInternal CreateObject(DbConnection owningObject) { 
            DbConnectionInternal newObj = null;
 
            try {
                newObj = _connectionFactory.CreatePooledConnection(owningObject, this, _connectionPoolGroup.ConnectionOptions);
                if (null == newObj) {
                    throw ADP.InternalError(ADP.InternalErrorCode.CreateObjectReturnedNull);    // CreateObject succeeded, but null object 
                }
                if (!newObj.CanBePooled) { 
                    throw ADP.InternalError(ADP.InternalErrorCode.NewObjectCannotBePooled);        // CreateObject succeeded, but non-poolable object 
                }
                newObj.PrePush(null); 

                lock (_objectList) {
                    _objectList.Add(newObj);
                    _totalObjects = _objectList.Count; 
                    PerformanceCounters.NumberOfPooledConnections.Increment();   //
                } 
                Bid.PoolerTrace(" %d#, Connection %d#, Added to pool.\n", ObjectID, newObj.ObjectID); 

                // Reset the error wait: 
                _errorWait = ERROR_WAIT_DEFAULT;
            }
            catch(Exception e)  {
                // 
                if (!ADP.IsCatchableExceptionType(e)) {
                    throw; 
                } 

                ADP.TraceExceptionForCapture(e); 

                newObj = null; // set to null, so we do not return bad new object
                // Failed to create instance
                _resError = e; 
                _waitHandles.ErrorEvent.Set();
                   _errorOccurred = true; 
                _errorTimer = new Timer(new TimerCallback(this.ErrorCallback), null, _errorWait, _errorWait); 

                if (30000 < _errorWait) { 
                    _errorWait = 60000;
                }
                else {
                    _errorWait *= 2; 
                }
                throw; 
            } 
            return newObj;
        } 

        private void DeactivateObject(DbConnectionInternal obj) {
            Bid.PoolerTrace(" %d#, Connection %d#, Deactivating.\n", ObjectID, obj.ObjectID);
 
            obj.DeactivateConnection(); // we presume this operation is safe outside of a lock...
 
            if ((State.Running == _state) && !obj.IsConnectionDoomed) { 
                bool returnToGeneralPool = true;
 
                lock (obj) {
                    // A connection with a delegated transaction cannot currently
                    // be returned to a different customer until the transaction
                    // actually completes, so we send it into Stasis -- the SysTx 
                    // transaction object will ensure that it is owned (not lost),
                    // and it will be certain to put it back into the pool. 
                    if (obj.IsNonPoolableTransactionRoot) { 
                        obj.SetInStasis();
                        returnToGeneralPool = false; 
                    }
                    else {
                        // We must put this connection into the transacted pool
                        // while inside a lock to prevent a race condition with 
                        // the transaction asyncronously completing on a second
                        // thread. 
                        SysTx.Transaction transaction = obj.EnlistedTransaction; 
                        if (null != transaction) {
                            TransactionBegin(transaction);  // Delayed creation of transacted pool 
                            _transactedConnectionPool.PutTransactedObject(transaction, obj);
                            returnToGeneralPool = false;
                        }
                    } 
                }
 
                // Only push the connection into the general pool if we didn't 
                // already push it onto the transacted pool.
                if (returnToGeneralPool) { 
                    PutNewObject(obj);
                }
            }
            else { 
                // the object is not fit for reuse -- just dispose of it.
                DestroyObject(obj); 
                QueuePoolCreateRequest(); 
            }
        } 

        private void DestroyObject(DbConnectionInternal obj) {
            // A connection with a delegated transaction cannot be disposed of
            // until the delegated transaction has actually completed.  Instead, 
            // we simply leave it alone; when the transaction completes, it will
            // come back through PutObjectFromTransactedPool, which will call us 
            // again. 
            if (obj.IsTxRootWaitingForTxEnd) {
                Bid.PoolerTrace(" %d#, Connection %d#, Has Delegated Transaction, waiting to Dispose.\n", ObjectID, obj.ObjectID); 
            }
            else {
                Bid.PoolerTrace(" %d#, Connection %d#, Removing from pool.\n", ObjectID, obj.ObjectID);
 
                bool removed = false;
                lock (_objectList) { 
                    removed = _objectList.Remove(obj); 
                    Debug.Assert(removed, "attempt to DestroyObject not in list");
                    _totalObjects = _objectList.Count; 
                }

                if (removed) {
                    Bid.PoolerTrace(" %d#, Connection %d#, Removed from pool.\n", ObjectID, obj.ObjectID); 
                    PerformanceCounters.NumberOfPooledConnections.Decrement();
                } 
                obj.Dispose(); 

                Bid.PoolerTrace(" %d#, Connection %d#, Disposed.\n", ObjectID, obj.ObjectID); 
                PerformanceCounters.HardDisconnectsPerSecond.Increment();
            }
        }
 
        private void ErrorCallback(Object state) {
            Bid.PoolerTrace(" %d#, Resetting Error handling.\n", ObjectID); 
 
            _errorOccurred = false;
            _waitHandles.ErrorEvent.Reset(); 
            Timer t     = _errorTimer;
            _errorTimer = null;
            if (t != null) {
                t.Dispose(); // Cancel timer request. 
            }
        } 
 
        internal DbConnectionInternal GetConnection(DbConnection owningObject) {
            DbConnectionInternal obj = null; 
            SysTx.Transaction transaction = null;

            PerformanceCounters.SoftConnectsPerSecond.Increment();
 
            if(_state != State.Running) {
                Bid.PoolerTrace(" %d#, DbConnectionInternal State != Running.\n", ObjectID); 
                return null; 
            }
 
            Bid.PoolerTrace(" %d#, Getting connection.\n", ObjectID);
            // If automatic transaction enlistment is required, then we try to
            // get the connection from the transacted connection pool first.
            if (HasTransactionAffinity) { 
                obj = GetFromTransactedPool(out transaction);
            } 
 
            if (null == obj) {
                Interlocked.Increment(ref _waitCount); 
                uint waitHandleCount = 3;
                uint timeout = (uint)CreationTimeout;

                do { 
                    int waitResult = BOGUS_HANDLE;
                    int releaseSemaphoreResult = 0; 
 
                    bool mustRelease = false;
                    RuntimeHelpers.PrepareConstrainedRegions(); 
                    try {
                        _waitHandles.DangerousAddRef(ref mustRelease);

                        // We absolutely must have the value of waitResult set, 
                        // or we may leak the mutex in async abort cases.
                        RuntimeHelpers.PrepareConstrainedRegions(); 
                        try { 
                            Debug.Assert(2 == waitHandleCount || 3 == waitHandleCount, "unexpected waithandle count");
                        } 
                        finally {
                            waitResult = SafeNativeMethods.WaitForMultipleObjectsEx(waitHandleCount, _waitHandles.DangerousGetHandle(), false, timeout, false);
                        }
 
                        // 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 WAIT_TIMEOUT:
                            Bid.PoolerTrace(" %d#, Wait timed out.\n", ObjectID); 
                            Interlocked.Decrement(ref _waitCount);
                            return null; 
 
                        case ERROR_HANDLE:
                            // Throw the error that PoolCreateRequest stashed. 
                            Bid.PoolerTrace(" %d#, Errors are set.\n", ObjectID);
                            Interlocked.Decrement(ref _waitCount);
                            throw _resError;
 
                        case CREATION_HANDLE:
                            Bid.PoolerTrace(" %d#, Creating new connection.\n", ObjectID); 
 
                            try {
                                obj = UserCreateRequest(owningObject); 
                            }
                            catch {
                                if (null == obj) {
                                    Interlocked.Decrement(ref _waitCount); 
                                }
                                throw; 
                            } 
                            finally {
                                // SQLBUDT #386664 - 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"); 
                                        waitHandleCount = 2;
                                    }
                                }
                            } 
                            break;
 
                        case SEMAPHORE_HANDLE: 
                            //
                            //    guaranteed available inventory 
                            //
                            Interlocked.Decrement(ref _waitCount);
                            obj = GetFromGeneralPool();
                            break; 

                        case WAIT_FAILED: 
                            Bid.PoolerTrace(" %d#, Wait failed.\n", ObjectID); 
                            Interlocked.Decrement(ref _waitCount);
                            Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 
                            goto default; // if ThrowExceptionForHR didn't throw for some reason
                        case (WAIT_ABANDONED+SEMAPHORE_HANDLE):
                            Bid.PoolerTrace(" %d#, Semaphore handle abandonded.\n", ObjectID);
                            Interlocked.Decrement(ref _waitCount); 
                            throw new AbandonedMutexException(SEMAPHORE_HANDLE,_waitHandles.PoolSemaphore);
                        case (WAIT_ABANDONED+ERROR_HANDLE): 
                            Bid.PoolerTrace(" %d#, Error handle abandonded.\n", ObjectID); 
                            Interlocked.Decrement(ref _waitCount);
                            throw new AbandonedMutexException(ERROR_HANDLE,_waitHandles.ErrorEvent); 
                        case (WAIT_ABANDONED+CREATION_HANDLE):
                            Bid.PoolerTrace(" %d#, Creation handle abandoned.\n", ObjectID);
                            Interlocked.Decrement(ref _waitCount);
                            throw new AbandonedMutexException(CREATION_HANDLE,_waitHandles.CreationSemaphore); 
                        default:
                            Bid.PoolerTrace(" %d#, WaitForMultipleObjects=%d\n", ObjectID, waitResult); 
                            Interlocked.Decrement(ref _waitCount); 
                            throw ADP.InternalError(ADP.InternalErrorCode.UnexpectedWaitAnyResult);
                        } 
                    }
                    finally {
                        if (CREATION_HANDLE == waitResult) {
                            int result = SafeNativeMethods.ReleaseSemaphore(_waitHandles.CreationHandle.DangerousGetHandle(), 1, IntPtr.Zero); 
                            if (0 == result) { // failure case
                                releaseSemaphoreResult = Marshal.GetHRForLastWin32Error(); 
                            } 
                        }
                        if (mustRelease) { 
                            _waitHandles.DangerousRelease();
                        }
                    }
                    if (0 != releaseSemaphoreResult) { 
                        Marshal.ThrowExceptionForHR(releaseSemaphoreResult); // will only throw if (hresult < 0)
                    } 
                } while (null == obj); 
            }
 
            if (null != obj) {
                lock (obj) {   // Protect against Clear and ReclaimEmancipatedObjects, which call IsEmancipated, which is affected by PrePush and PostPop
                    obj.PostPop(owningObject);
                } 
                try {
                    obj.ActivateConnection(transaction); 
                } 
                catch(SecurityException) {
                    // if Activate throws an exception 
                    // put it back in the pool or have it properly disposed of
                    this.PutObject(obj, owningObject);
                    throw;
                } 
            }
            return(obj); 
        } 

        private DbConnectionInternal GetFromGeneralPool() { 
            DbConnectionInternal obj = null;

            obj = _stackNew.SynchronizedPop();
            if (null == obj) { 
                obj = _stackOld.SynchronizedPop();
            } 
 
            // SQLBUDT #356870 -- When another thread is clearing this pool,
            // it will remove all connections in this pool which causes the 
            // following assert to fire, which really mucks up stress against
            //  checked bits.  The assert is benign, so we're commenting it out.
            //Debug.Assert(obj != null, "GetFromGeneralPool called with nothing in the pool!");
 
            if (null != obj) {
                Bid.PoolerTrace(" %d#, Connection %d#, Popped from general pool.\n", ObjectID, obj.ObjectID); 
                PerformanceCounters.NumberOfFreeConnections.Decrement(); 
            }
            return(obj); 
        }

        private DbConnectionInternal GetFromTransactedPool(out SysTx.Transaction transaction) {
            transaction = ADP.GetCurrentTransaction(); 
            DbConnectionInternal obj = null;
 
            if (null != transaction && null != _transactedConnectionPool) { 
                obj = _transactedConnectionPool.GetTransactedObject(transaction);
 
                if (null != obj) {
                    Bid.PoolerTrace(" %d#, Connection %d#, Popped from transacted pool.\n", ObjectID, obj.ObjectID);
                    PerformanceCounters.NumberOfFreeConnections.Decrement();
                } 
            }
            return obj; 
        } 

        private void PoolCreateRequest(object state) { 
            // called by pooler to ensure pool requests are currently being satisfied -
            // creation mutex has not been obtained

            IntPtr hscp; 

            Bid.PoolerScopeEnter(out hscp, " %d#\n", ObjectID); 
 
            try {
                if (State.Running == _state) { 
                    // Before creating any new objects, reclaim any released objects that were
                    // not closed.
                    ReclaimEmancipatedObjects();
 
                    if (!ErrorOccurred) {
                        if (NeedToReplenish) { 
                            // Check to see if pool was created using integrated security and if so, make 
                            // sure the identity of current user matches that of user that created pool.
                            // If it doesn't match, do not create any objects on the ThreadPool thread, 
                            // since either Open will fail or we will open a object for this pool that does
                            // not belong in this pool.  The side effect of this is that if using integrated
                            // security min pool size cannot be guaranteed.
                            if (UsingIntegrateSecurity && !_identity.Equals(DbConnectionPoolIdentity.GetCurrent())) { 
                                return;
                            } 
                            bool mustRelease = false; 
                            int waitResult = BOGUS_HANDLE;
                            uint timeout = (uint)CreationTimeout; 

                            RuntimeHelpers.PrepareConstrainedRegions();
                            try {
                                _waitHandles.DangerousAddRef(ref mustRelease); 

                                // Obtain creation mutex so we're the only one creating objects 
                                // and we must have the wait result 
                                RuntimeHelpers.PrepareConstrainedRegions();
                                try { } finally { 
                                    waitResult = SafeNativeMethods.WaitForSingleObjectEx(_waitHandles.CreationHandle.DangerousGetHandle(), timeout, false);
                                }
                                if (WAIT_OBJECT_0 == waitResult) {
                                    DbConnectionInternal newObj; 

                                    // Check ErrorOccurred again after obtaining mutex 
                                    if (!ErrorOccurred) { 
                                        while (NeedToReplenish) {
                                            newObj = CreateObject((DbConnection)null); 

                                            // We do not need to check error flag here, since we know if
                                            // CreateObject returned null, we are in error case.
                                            if (null != newObj) { 
                                                PutNewObject(newObj);
                                            } 
                                            else { 
                                                break;
                                            } 
                                        }
                                    }
                                }
                                else if (WAIT_TIMEOUT == waitResult) { 
                                    // do not wait forever and potential block this worker thread
                                    // instead wait for a period of time and just requeue to try again 
                                    QueuePoolCreateRequest(); 
                                }
                                else { 
                                    // trace waitResult and ignore the failure
                                    Bid.PoolerTrace(" %d#, PoolCreateRequest called WaitForSingleObject failed %d", ObjectID, waitResult);
                                }
                            } 
                            catch (Exception e) {
                                // 
                                if (!ADP.IsCatchableExceptionType(e)) { 
                                    throw;
                                } 

                                // Now that CreateObject can throw, we need to catch the exception and discard it.
                                // There is no further action we can take beyond tracing.  The error will be
                                // thrown to the user the next time they request a connection. 
                                Bid.PoolerTrace(" %d#, PoolCreateRequest called CreateConnection which threw an exception: " + e.ToString(), ObjectID);
                            } 
                            finally { 
                                if (WAIT_OBJECT_0 == waitResult) {
                                    // reuse waitResult and ignore its value 
                                    waitResult = SafeNativeMethods.ReleaseSemaphore(_waitHandles.CreationHandle.DangerousGetHandle(), 1, IntPtr.Zero);
                                }
                                if (mustRelease) {
                                    _waitHandles.DangerousRelease(); 
                                }
                            } 
                        } 
                    }
                } 
            }
            finally {
                Bid.ScopeLeave(ref hscp);
            } 
        }
 
        private void ProcessDeactivateQueue(object state) { 
            IntPtr hscp;
 
            Bid.PoolerScopeEnter(out hscp, " %d#\n", ObjectID);

            try {
                object[] deactivateQueue; 
                lock (_deactivateQueue.SyncRoot) {
                    deactivateQueue = _deactivateQueue.ToArray(); 
                    _deactivateQueue.Clear(); 
                }
 
                foreach (DbConnectionInternal obj in deactivateQueue) {
                    PerformanceCounters.NumberOfStasisConnections.Decrement();
                    DeactivateObject(obj);
                } 
            }
            finally { 
                Bid.ScopeLeave(ref hscp); 
            }
        } 

        internal void PutNewObject(DbConnectionInternal obj) {
            Debug.Assert(null != obj,        "why are we adding a null object to the pool?");
            Debug.Assert(obj.CanBePooled,    "non-poolable object in pool"); 

            Bid.PoolerTrace(" %d#, Connection %d#, Pushing to general pool.\n", ObjectID, obj.ObjectID); 
 
            _stackNew.SynchronizedPush(obj);
            _waitHandles.PoolSemaphore.Release(1); 
            PerformanceCounters.NumberOfFreeConnections.Increment();

        }
 
        internal void PutObject(DbConnectionInternal obj, object owningObject) {
            Debug.Assert(null != obj, "null obj?"); 
 
            PerformanceCounters.SoftDisconnectsPerSecond.Increment();
 
            // Once a connection is closing (which is the state that we're in at
            // this point in time) you cannot delegate a transaction to or enlist
            // a transaction in it, so we can correctly presume that if there was
            // not a delegated or enlisted transaction to start with, that there 
            // will not be a delegated or enlisted transaction once we leave the
            // lock. 
 
            lock (obj) {
                // Calling PrePush prevents the object from being reclaimed 
                // once we leave the lock, because it sets _pooledCount such
                // that it won't appear to be out of the pool.  What that
                // means, is that we're now responsible for this connection:
                // it won't get reclaimed if we drop the ball somewhere. 
                obj.PrePush(owningObject);
 
                // 
            }
 
            if (UseDeactivateQueue) {
                // If we're using the DeactivateQueue, we'll just queue it up and
                // be done; all the hard work will be done on the despooler thread.
 
                bool needToQueueWorkItem;
 
                Bid.PoolerTrace(" %d#, Connection %d#, Queueing for deactivation.\n", ObjectID, obj.ObjectID); 
                PerformanceCounters.NumberOfStasisConnections.Increment();
 
                lock (_deactivateQueue.SyncRoot) {
                    needToQueueWorkItem = (0 == _deactivateQueue.Count);
                    _deactivateQueue.Enqueue(obj);
                } 
                if (needToQueueWorkItem) {
                    // Make sure we actually get around to deactivating the object 
                    // and making it available again. 
                    ThreadPool.QueueUserWorkItem(_deactivateCallback, null);
                } 
            }
            else {
                // no deactivate queue -- do the work right now.
                DeactivateObject(obj); 
            }
        } 
 
        internal void PutObjectFromTransactedPool(DbConnectionInternal obj) {
            Debug.Assert(null != obj, "null pooledObject?"); 
            Debug.Assert(!obj.HasEnlistedTransaction, "pooledObject is still enlisted?");

            // called by the transacted connection pool , once it's removed the
            // connection from it's list.  We put the connection back in general 
            // circulation.
 
            // NOTE: there is no locking required here because if we're in this 
            // method, we can safely presume that the caller is the only person
            // that is using the connection, and that all pre-push logic has been 
            // done and all transactions are ended.

            Bid.PoolerTrace(" %d#, Connection %d#, Transaction has ended.\n", ObjectID, obj.ObjectID);
 
            if (_state == State.Running && obj.CanBePooled) {
                PutNewObject(obj); 
            } 
            else {
                DestroyObject(obj); 
                QueuePoolCreateRequest();
            }
        }
 
        private void QueuePoolCreateRequest() {
            if (State.Running == _state) { 
                // Make sure we're at quota by posting a callback to the threadpool. 
                ThreadPool.QueueUserWorkItem(_poolCreateRequest);
            } 
        }

        private bool ReclaimEmancipatedObjects() {
            bool emancipatedObjectFound = false; 

            Bid.PoolerTrace(" %d#\n", ObjectID); 
 
            List reclaimedObjects = new List();
            int count; 

            lock(_objectList) {
                count = _objectList.Count;
 
                for (int i = 0; i < count; ++i) {
                    DbConnectionInternal obj = _objectList[i]; 
 
                    if (null != obj) {
                        bool locked = false; 

                        try {
                            locked = Monitor.TryEnter(obj);
 
                            if (locked) { // avoid race condition with PrePush/PostPop and IsEmancipated
                                if (obj.IsEmancipated) { 
                                    // Inside the lock, we want to do as little 
                                    // as possible, so we simply mark the object
                                    // as being in the pool, but hand it off to 
                                    // an out of pool list to be deactivated,
                                    // etc.
                                    obj.PrePush(null);
                                    reclaimedObjects.Add(obj); 
                                }
                            } 
                        } 
                        finally {
                            if (locked) 
                                Monitor.Exit(obj);
                        }
                    }
                } 
            }
 
            // NOTE: we don't want to call DeactivateObject while we're locked, 
            // because it can make roundtrips to the server and this will block
            // object creation in the pooler.  Instead, we queue things we need 
            // to do up, and process them outside the lock.
            count = reclaimedObjects.Count;

            for (int i = 0; i < count; ++i) { 
                DbConnectionInternal obj = reclaimedObjects[i];
 
                Bid.PoolerTrace(" %d#, Connection %d#, Reclaiming.\n", ObjectID, obj.ObjectID); 
                PerformanceCounters.NumberOfReclaimedConnections.Increment();
 
                emancipatedObjectFound = true;

                // NOTE: it is not possible for us to have a connection that has
                // a delegated transaction at this point, because IsEmancipated 
                // would not have returned true if it did, and when a connection
                // is emancipated, you can't enlist in a transaction (because you 
                // can't get to it to make the call...) 
                DeactivateObject(obj);
            } 
            return emancipatedObjectFound;
        }

        internal void Startup() { 
            Bid.PoolerTrace(" %d#, CleanupWait=%d\n", ObjectID, _cleanupWait);
 
            _cleanupTimer = CreateCleanupTimer(); 
            if (NeedToReplenish) {
                QueuePoolCreateRequest(); 
            }
        }

        internal void Shutdown() { 
            Bid.PoolerTrace(" %d#\n", ObjectID);
 
            _state = State.ShuttingDown; 

            Timer t; // deactivate timer callbacks 

            t = _cleanupTimer;
            _cleanupTimer = null;
            if (null != t) { 
                t.Dispose();
            } 
 
            t = _errorTimer;
            _errorTimer = null; 
            if (null != t) {
                t.Dispose();
            }
        } 

        internal void TransactionBegin(SysTx.Transaction transaction) { 
            TransactedConnectionPool transactedConnectionPool = _transactedConnectionPool; 
            if (null != transactedConnectionPool) {
                transactedConnectionPool.TransactionBegin(transaction); 
            }
        }

        internal void TransactionEnded(SysTx.Transaction transaction, DbConnectionInternal transactedObject) { 
            Debug.Assert(null != transaction, "null transaction?");
            Debug.Assert(null != transactedObject, "null transactedObject?"); 
            // Note: connection may still be associated with transaction due to Explicit Unbinding requirement. 

            Bid.PoolerTrace(" %d#, Transaction %d#, Connection %d#, Transaction Completed\n", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID); 

            // called by the internal connection when it get's told that the
            // transaction is completed.  We tell the transacted pool to remove
            // the connection from it's list, then we put the connection back in 
            // general circulation.
 
            TransactedConnectionPool transactedConnectionPool = _transactedConnectionPool; 
            if (null != transactedConnectionPool) {
                transactedConnectionPool.TransactionEnded(transaction, transactedObject); 
            }
        }

        private DbConnectionInternal UserCreateRequest(DbConnection owningObject) { 
            // called by user when they were not able to obtain a free object but
            // instead obtained creation mutex 
 
            DbConnectionInternal obj = null;
            if (ErrorOccurred) { 
               throw _resError;
            }
            else {
                 if ((Count < MaxPoolSize) || (0 == MaxPoolSize)) { 
                    // If we have an odd number of total objects, reclaim any dead objects.
                    // If we did not find any objects to reclaim, create a new one. 
 
                    //
                     if ((Count & 0x1) == 0x1 || !ReclaimEmancipatedObjects()) 
                        obj = CreateObject(owningObject);
                }
                return obj;
            } 
        }
 
        private class DbConnectionInternalListStack { 
            private DbConnectionInternal _stack;
#if DEBUG 
            private int _version;
            private int _count;
#endif
            internal DbConnectionInternalListStack() { 
            }
 
            internal int Count { 
                get {
                    int count = 0; 
                    lock(this) {
                        for(DbConnectionInternal x = _stack; null != x; x = x.NextPooledObject) {
                            ++count;
                        } 
                    }
#if DEBUG 
                    Debug.Assert(count == _count, "count is corrupt"); 
#endif
                    return count; 
                }
            }

            internal DbConnectionInternal SynchronizedPop() { 
                DbConnectionInternal value;
                lock(this) { 
                    value = _stack; 
                    if (null != value) {
                        _stack = value.NextPooledObject; 
                        value.NextPooledObject = null;
#if DEBUG
                        _version++;
                        _count--; 
#endif
                    } 
#if DEBUG 
                    Debug.Assert((null != value || 0 == _count) && (0 <= _count), "broken SynchronizedPop");
#endif 
                }
                return value;
            }
 
            internal void SynchronizedPush(DbConnectionInternal value) {
                Debug.Assert(null != value, "pushing null value"); 
                lock(this) { 
#if DEBUG
                    Debug.Assert(null == value.NextPooledObject, "pushing value with non-null NextPooledObject"); 
                    int index = 0;
                    for(DbConnectionInternal x = _stack; null != x; x = x.NextPooledObject, ++index) {
                        Debug.Assert(x != value, "double push: connection already in stack");
                    } 
                    Debug.Assert(_count == index, "SynchronizedPush count is corrupt");
#endif 
                    value.NextPooledObject = _stack; 
                    _stack = value;
#if DEBUG 
                    _version++;
                    _count++;
#endif
                } 
            }
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
namespace System.Data.ProviderBase { 

    using System; 
    using System.Collections;
    using System.Collections.Generic;
    using System.Data.Common;
    using System.Diagnostics; 
    using System.Globalization;
    using System.Runtime.CompilerServices; 
    using System.Runtime.ConstrainedExecution; 
    using System.Runtime.InteropServices;
    using System.Security; 
    using System.Security.Permissions;
    using System.Security.Principal;
    using System.Threading;
    using SysTx = System.Transactions; 

    sealed internal class DbConnectionPool { 
        private enum State { 
            Initializing,
            Running, 
            ShuttingDown,
        }

        internal const Bid.ApiGroup PoolerTracePoints = (Bid.ApiGroup)0x1000; 

        // Hotfix: SQLBUVSTS01 # 272199: Hotfix request for RFC #50003517 
        // [PS SQL Hotfix RFC # 50003517: Current Transaction is disposed within the transaction scope, 
        //      before leaving TransactionScope block against SQL Server 2008]
        // This class is a way to stash our cloned Tx key for later disposal when it's no longer needed. 
        // We can't get at the key in the dictionary without enumerating entries, so we stash an extra
        // copy as part of the value.
        sealed private class TransactedConnectionList : List {
            private SysTx.Transaction _transaction; 
            internal TransactedConnectionList(int initialAllocation, SysTx.Transaction tx) : base(initialAllocation) {
                _transaction = tx; 
            } 

            internal void Dispose() { 
                if (null != _transaction) {
                    _transaction.Dispose();
                }
            } 
        }
 
        sealed private class TransactedConnectionPool : Dictionary { 
            DbConnectionPool _pool;
 
            private static int _objectTypeCount; // Bid counter
            internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);

            internal TransactedConnectionPool(DbConnectionPool pool) : base() { 
                Debug.Assert(null != pool, "null pool?");
 
                _pool = pool; 
                Bid.PoolerTrace(" %d#, Constructed for connection pool %d#\n", ObjectID, _pool.ObjectID);
            } 

            internal int ObjectID {
                get {
                    return _objectID; 
                }
            } 
 
            internal DbConnectionPool Pool {
                get { 
                    return _pool;
                }
            }
 
            internal DbConnectionInternal GetTransactedObject(SysTx.Transaction transaction) {
                Debug.Assert(null != transaction, "null transaction?"); 
 
                DbConnectionInternal transactedObject = null;
 
                TransactedConnectionList connections;

                if (this.TryGetValue(transaction, out connections)) {
                    lock (connections) { 
                        int i = connections.Count - 1;
                        if (0 <= i) { 
                            transactedObject = connections[i]; 
                            connections.RemoveAt(i);
                        } 
                    }
                }

                if (null != transactedObject) { 
                    Bid.PoolerTrace(" %d#, Transaction %d#, Connection %d#, Popped.\n", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID);
                } 
                return transactedObject; 
            }
 
            internal void PutTransactedObject(SysTx.Transaction transaction, DbConnectionInternal transactedObject) {
                Debug.Assert(null != transaction, "null transaction?");
                Debug.Assert(null != transactedObject, "null transactedObject?");
 
                Bid.PoolerTrace(" %d#, Transaction %d#, Connection %d#, Pushing.\n", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID);
 
                TransactedConnectionList connections; 

                // NOTE: it is possible that the connecton was put on the 
                //       deactivate queue, and while it was on the queue, the
                //       transaction ended, causing the list for the transaction
                //       to have been removed.  In that case, we can't expect
                //       the list to be here. 
                if (this.TryGetValue(transaction, out connections)) {
                    lock (connections) { 
                        Debug.Assert(0 > connections.IndexOf(transactedObject), "adding to pool a second time?"); 
                        connections.Add(transactedObject);
                        Pool.PerformanceCounters.NumberOfFreeConnections.Increment(); 
                    }
                }
            }
 
            internal void TransactionBegin(SysTx.Transaction transaction) {
                Bid.PoolerTrace(" %d#, Transaction %d#, Begin.\n", ObjectID, transaction.GetHashCode()); 
 
                TransactedConnectionList connections;
 
                if (!this.TryGetValue(transaction, out connections)) {
                    SysTx.Transaction transactionClone = null;
                    try {
                        transactionClone = transaction.Clone(); 
                        TransactedConnectionList newConnections = new TransactedConnectionList(2, transactionClone); // start with only two connections in the list; most times we won't need that many.
 
                        Bid.PoolerTrace(" %d#, Transaction %d#, Adding List to transacted pool.\n", ObjectID, transaction.GetHashCode()); 
                        lock (this) {
                            if (!this.TryGetValue(transaction, out connections)) { 
                                connections = newConnections;
                                this.Add(transactionClone, connections);
                                transactionClone = null; // we've used it -- don't throw it away.
                            } 
                        }
                    } 
                    finally { 
                        if (null != transactionClone) {
                            transactionClone.Dispose(); 
                        }
                    }
                    Bid.PoolerTrace(" %d#, Transaction %d#, Added.\n", ObjectID, transaction.GetHashCode());
                } 
            }
 
            internal void TransactionEnded(SysTx.Transaction transaction, DbConnectionInternal transactedObject) { 
                Bid.PoolerTrace(" %d#, Transaction %d#, Connection %d#, Transaction Completed\n", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID);
 
                TransactedConnectionList connections;
                int entry = -1;

                // NOTE: we may be ending a transaction for a connection that is 
                //       currently not in the pool, and therefore it may not have
                //       a list for it, because it may have been removed already. 
                if (this.TryGetValue(transaction, out connections)) { 
                    lock (connections) {
                        entry = connections.IndexOf(transactedObject); 

                        if (entry >= 0) {
                            connections.RemoveAt(entry);
                        } 

                        // Once we've completed all the ended notifications, we can 
                        // safely remove the list from the transacted pool. 
                        if (0 >= connections.Count) {
                            Bid.PoolerTrace(" %d#, Transaction %d#, Removing List from transacted pool.\n", ObjectID, transaction.GetHashCode()); 
                            lock (this) {
                                Remove(transaction);
                            }
                            Bid.PoolerTrace(" %d#, Transaction %d#, Removed.\n", ObjectID, transaction.GetHashCode()); 

                            // we really need to dispose our connection list; it may have 
                            // native resources via the tx and GC may not happen soon enough. 
                            connections.Dispose();
                        } 
                    }
                }

                // If (and only if) we found the connection in the list of 
                // connections, we'll put it back...
                if (0 <= entry)  { 
                    Pool.PerformanceCounters.NumberOfFreeConnections.Decrement(); 
                    Pool.PutObjectFromTransactedPool(transactedObject);
                } 
            }
        }

        private sealed class PoolWaitHandles : DbBuffer { 

            private readonly Semaphore _poolSemaphore; 
            private readonly ManualResetEvent _errorEvent; 

            // Using a Mutex requires ThreadAffinity because SQL CLR can swap 
            // the underlying Win32 thread associated with a managed thread in preemptive mode.
            // Using an AutoResetEvent does not have that complication.
            private readonly Semaphore _creationSemaphore;
 
            private readonly SafeHandle _poolHandle;
            private readonly SafeHandle _errorHandle; 
            private readonly SafeHandle _creationHandle; 

            private readonly int _releaseFlags; 

            internal PoolWaitHandles(Semaphore poolSemaphore, ManualResetEvent errorEvent, Semaphore creationSemaphore) : base(3*IntPtr.Size) {
                bool mustRelease1 = false, mustRelease2 = false, mustRelease3 = false;
                RuntimeHelpers.PrepareConstrainedRegions(); 
                try {
                    _poolSemaphore     = poolSemaphore; 
                    _errorEvent        = errorEvent; 
                    _creationSemaphore = creationSemaphore;
 
                    // because SafeWaitHandle doesn't have reliability contract
                    _poolHandle     = poolSemaphore.SafeWaitHandle;
                    _errorHandle    = errorEvent.SafeWaitHandle;
                    _creationHandle = creationSemaphore.SafeWaitHandle; 

                    _poolHandle.DangerousAddRef(ref mustRelease1); 
                    _errorHandle.DangerousAddRef(ref mustRelease2); 
                    _creationHandle.DangerousAddRef(ref mustRelease3);
 
                    Debug.Assert(0 == SEMAPHORE_HANDLE, "SEMAPHORE_HANDLE");
                    Debug.Assert(1 == ERROR_HANDLE, "ERROR_HANDLE");
                    Debug.Assert(2 == CREATION_HANDLE, "CREATION_HANDLE");
 
                    WriteIntPtr(SEMAPHORE_HANDLE*IntPtr.Size, _poolHandle.DangerousGetHandle());
                    WriteIntPtr(ERROR_HANDLE*IntPtr.Size,     _errorHandle.DangerousGetHandle()); 
                    WriteIntPtr(CREATION_HANDLE*IntPtr.Size,  _creationHandle.DangerousGetHandle()); 
                }
                finally { 
                    if (mustRelease1) {
                        _releaseFlags |= 1;
                    }
                    if (mustRelease2) { 
                        _releaseFlags |= 2;
                    } 
                    if (mustRelease3) { 
                        _releaseFlags |= 4;
                    } 
                }
            }

            internal SafeHandle CreationHandle { 
                [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
                get { return _creationHandle; } 
            } 

            internal Semaphore CreationSemaphore { 
                get { return _creationSemaphore; }
            }

            internal ManualResetEvent ErrorEvent { 
                get { return _errorEvent; }
            } 
 
            internal Semaphore PoolSemaphore {
                get { return _poolSemaphore; } 
            }

            protected override bool ReleaseHandle() {
                // NOTE: The SafeHandle class guarantees this will be called exactly once. 
                // we know we can touch these other managed objects because of our original DangerousAddRef
                if (0 != (1 & _releaseFlags)) { 
                    _poolHandle.DangerousRelease(); 
                }
                if (0 != (2 & _releaseFlags)) { 
                    _errorHandle.DangerousRelease();
                }
                if (0 != (4 & _releaseFlags)) {
                    _creationHandle.DangerousRelease(); 
                }
                return base.ReleaseHandle(); 
            } 
        }
 
        private const int MAX_Q_SIZE    = (int)0x00100000;

        // The order of these is important; we want the WaitAny call to be signaled
        // for a free object before a creation signal.  Only the index first signaled 
        // object is returned from the WaitAny call.
        private const int SEMAPHORE_HANDLE = (int)0x0; 
        private const int ERROR_HANDLE     = (int)0x1; 
        private const int CREATION_HANDLE  = (int)0x2;
        private const int BOGUS_HANDLE     = (int)0x3; 

        private const int WAIT_OBJECT_0 = 0;
        private const int WAIT_TIMEOUT   = (int)0x102;
        private const int WAIT_ABANDONED = (int)0x80; 
        private const int WAIT_FAILED    = -1;
 
        private const int ERROR_WAIT_DEFAULT = 5 * 1000; // 5 seconds 

        // we do want a testable, repeatable set of generated random numbers 
        private static readonly Random _random = new Random(5101977); // Value obtained from Dave Driver

        private readonly int              _cleanupWait;
        private readonly DbConnectionPoolIdentity _identity; 

        private readonly DbConnectionFactory          _connectionFactory; 
        private readonly DbConnectionPoolGroup        _connectionPoolGroup; 
        private readonly DbConnectionPoolGroupOptions _connectionPoolGroupOptions;
        private          DbConnectionPoolProviderInfo _connectionPoolProviderInfo; 

        private State                     _state;

        private readonly DbConnectionInternalListStack _stackOld = new DbConnectionInternalListStack(); 
        private readonly DbConnectionInternalListStack _stackNew = new DbConnectionInternalListStack();
 
        private readonly WaitCallback     _poolCreateRequest; 

        private readonly Queue            _deactivateQueue; 
        private readonly WaitCallback     _deactivateCallback;

        private int                       _waitCount;
        private readonly PoolWaitHandles  _waitHandles; 

        private Exception                 _resError; 
        private volatile bool             _errorOccurred; 

        private int                       _errorWait; 
        private Timer                     _errorTimer;

        private Timer                     _cleanupTimer;
 
        private readonly TransactedConnectionPool _transactedConnectionPool;
 
        private readonly List _objectList; 
        private int                       _totalObjects;
 
        private static int _objectTypeCount; // Bid counter
        internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);

        // only created by DbConnectionPoolGroup.GetConnectionPool 
        internal DbConnectionPool(
                            DbConnectionFactory connectionFactory, 
                            DbConnectionPoolGroup connectionPoolGroup, 
                            DbConnectionPoolIdentity identity,
                            DbConnectionPoolProviderInfo connectionPoolProviderInfo ) { 
            Debug.Assert(ADP.IsWindowsNT, "Attempting to construct a connection pool on Win9x?");
            Debug.Assert(null != connectionPoolGroup, "null connectionPoolGroup");

            if ((null != identity) && identity.IsRestricted) { 
                throw ADP.InternalError(ADP.InternalErrorCode.AttemptingToPoolOnRestrictedToken);
            } 
 
            _state= State.Initializing;
 
            lock(_random) { // Random.Next is not thread-safe
                _cleanupWait = _random.Next(12, 24)*10*1000; // 2-4 minutes in 10 sec intervals, WebData 103603
            }
 
            _connectionFactory = connectionFactory;
            _connectionPoolGroup = connectionPoolGroup; 
            _connectionPoolGroupOptions = connectionPoolGroup.PoolGroupOptions; 
            _connectionPoolProviderInfo = connectionPoolProviderInfo;
            _identity = identity; 

            if (UseDeactivateQueue) {
                _deactivateQueue = new Queue();
                _deactivateCallback = new WaitCallback(ProcessDeactivateQueue); 
            }
 
            _waitHandles = new PoolWaitHandles( 
                                new Semaphore(0, MAX_Q_SIZE),
                                new ManualResetEvent(false), 
                                new Semaphore(1, 1));

            _errorWait      = ERROR_WAIT_DEFAULT;
            _errorTimer     = null;  // No error yet. 

            _objectList     = new List(MaxPoolSize); 
 
            if(ADP.IsPlatformNT5) {
                _transactedConnectionPool = new TransactedConnectionPool(this); 
            }

            _poolCreateRequest = new WaitCallback(PoolCreateRequest); // used by CleanupCallback
            _state = State.Running; 

            Bid.PoolerTrace(" %d#, Constructed.\n", ObjectID); 
 
            //_cleanupTimer & QueuePoolCreateRequest is delayed until DbConnectionPoolGroup calls
            // StartBackgroundCallbacks after pool is actually in the collection 
        }

        private int CreationTimeout {
            get { return PoolGroupOptions.CreationTimeout; } 
        }
 
        internal int Count { 
            get { return _totalObjects; }
        } 

        internal DbConnectionFactory ConnectionFactory {
            get { return _connectionFactory; }
        } 

        internal bool ErrorOccurred { 
            get { return _errorOccurred; } 
        }
 
        private bool HasTransactionAffinity {
            get { return PoolGroupOptions.HasTransactionAffinity; }
        }
 
        internal TimeSpan LoadBalanceTimeout {
            get { return PoolGroupOptions.LoadBalanceTimeout; } 
        } 

        private bool NeedToReplenish { 
            get {
                if (State.Running != _state) // SQL BU DT 364595 - don't allow connection create when not running.
                    return false;
 
                int totalObjects = Count;
 
                if (totalObjects >= MaxPoolSize) 
                    return false;
 
                if (totalObjects < MinPoolSize)
                    return true;

                int freeObjects        = (_stackNew.Count + _stackOld.Count); 
                int waitingRequests    = _waitCount;
                bool needToReplenish = (freeObjects < waitingRequests) || ((freeObjects == waitingRequests) && (totalObjects > 1)); 
 
                return needToReplenish;
            } 
        }

        internal DbConnectionPoolIdentity Identity {
            get { return _identity; } 
        }
 
        internal bool IsRunning { 
            get { return State.Running == _state; }
        } 

        private int MaxPoolSize {
            get { return PoolGroupOptions.MaxPoolSize; }
        } 

        private int MinPoolSize { 
            get { return PoolGroupOptions.MinPoolSize; } 
        }
 
        internal int ObjectID {
            get {
                return _objectID;
            } 
        }
 
        internal DbConnectionPoolCounters PerformanceCounters { 
            get { return _connectionFactory.PerformanceCounters; }
        } 

        internal DbConnectionPoolGroup PoolGroup {
            get { return _connectionPoolGroup; }
        } 

        internal DbConnectionPoolGroupOptions PoolGroupOptions { 
            get { return _connectionPoolGroupOptions; } 
        }
 
        internal DbConnectionPoolProviderInfo ProviderInfo {
            get { return _connectionPoolProviderInfo; }
        }
 
        private bool UseDeactivateQueue {
            get { return PoolGroupOptions.UseDeactivateQueue; } 
        } 

        internal bool UseLoadBalancing { 
            get { return PoolGroupOptions.UseLoadBalancing; }
        }

        private bool UsingIntegrateSecurity { 
            get { return (null != _identity && DbConnectionPoolIdentity.NoIdentity != _identity); }
        } 
 
        private void CleanupCallback(Object state) {
            // Called when the cleanup-timer ticks over. 

            // This is the automatic prunning method.  Every period, we will
            // perform a two-step process:
            // 
            // First, for each free object above MinPoolSize, we will obtain a
            // semaphore representing one object and destroy one from old stack. 
            // We will continue this until we either reach MinPoolSize, we are 
            // unable to obtain a free object, or we have exhausted all the
            // objects on the old stack. 
            //
            // Second we move all free objects on the new stack to the old stack.
            // So, every period the objects on the old stack are destroyed and
            // the objects on the new stack are pushed to the old stack.  All 
            // objects that are currently out and in use are not on either stack.
            // 
            // With this logic, objects are pruned from the pool if unused for 
            // at least one period but not more than two periods.
 
            Bid.PoolerTrace(" %d#\n", ObjectID);

            // Destroy free objects that put us above MinPoolSize from old stack.
            while(Count > MinPoolSize) { // While above MinPoolSize... 

                if (_waitHandles.PoolSemaphore.WaitOne(0, false) /* != WAIT_TIMEOUT */) { 
                    // We obtained a objects from the semaphore. 
                    DbConnectionInternal obj = _stackOld.SynchronizedPop();
 
                    if (null != obj) {
                        // If we obtained one from the old stack, destroy it.
                        PerformanceCounters.NumberOfFreeConnections.Decrement();
 
                        // Transaction roots must survive even aging out (TxEnd event will clean them up).
                        bool shouldDestroy = true; 
                        lock (obj) {    // Lock to prevent ---- window between IsTransactionRoot and shouldDestroy assignment 
                            if (obj.IsTransactionRoot) {
                                shouldDestroy = false; 
                            }
                        }

                        // !!!!!!!!!! WARNING !!!!!!!!!!!!! 
                        //   ONLY touch obj after lock release if shouldDestroy is false!!!  Otherwise, it may be destroyed
                        //   by transaction-end thread! 
 
                        // Note that there is a minor race condition between this task and the transaction end event, if the latter runs
                        //  between the lock above and the SetInStasis call below. The reslult is that the stasis counter may be 
                        //  incremented without a corresponding decrement (the transaction end task is normally expected
                        //  to decrement, but will only do so if the stasis flag is set when it runs). I've minimized the size
                        //  of the window, but we aren't totally eliminating it due to SetInStasis needing to do bid tracing, which
                        //  we don't want to do under this lock, if possible. It should be possible to eliminate this ---- with 
                        //  more substantial re-architecture of the pool, but we don't have the time to do that work for the current release.
 
                        if (shouldDestroy) { 
                            DestroyObject(obj);
                        } 
                        else {
                            obj.SetInStasis();
                        }
                    } 
                    else {
                        // Else we exhausted the old stack (the object the 
                        // semaphore represents is on the new stack), so break. 
                        _waitHandles.PoolSemaphore.Release(1);
                        break; 
                    }
                }
                else {
                    break; 
                }
            } 
 
            // Push to the old-stack.  For each free object, move object from
            // new stack to old stack. 
            if(_waitHandles.PoolSemaphore.WaitOne(0, false) /* != WAIT_TIMEOUT */) {
                for(;;) {
                    DbConnectionInternal obj = _stackNew.SynchronizedPop();
 
                    if (null == obj)
                        break; 
 
                    Bid.PoolerTrace(" %d#, ChangeStacks=%d#\n", ObjectID, obj.ObjectID);
 
                    Debug.Assert(!obj.IsEmancipated, "pooled object not in pool");
                    Debug.Assert(obj.CanBePooled,     "pooled object is not poolable");

                    _stackOld.SynchronizedPush(obj); 
                }
                _waitHandles.PoolSemaphore.Release(1); 
            } 

            // Queue up a request to bring us up to MinPoolSize 
            QueuePoolCreateRequest();
        }

        internal void Clear() { 
            Bid.PoolerTrace(" %d#, Clearing.\n", ObjectID);
 
            DbConnectionInternal obj; 

            // First, quickly doom everything. 
            lock(_objectList) {
                int count = _objectList.Count;

                for (int i = 0; i < count; ++i) { 
                    obj = _objectList[i];
 
                    if (null != obj) { 
                        obj.DoNotPoolThisConnection();
                    } 
                }
            }

            // Second, dispose of all the free connections. 
            while (null != (obj = _stackNew.SynchronizedPop())) {
                PerformanceCounters.NumberOfFreeConnections.Decrement(); 
                DestroyObject(obj); 
            }
            while (null != (obj = _stackOld.SynchronizedPop())) { 
                PerformanceCounters.NumberOfFreeConnections.Decrement();
                DestroyObject(obj);
            }
 
            // Finally, reclaim everything that's emancipated (which, because
            // it's been doomed, will cause it to be disposed of as well) 
            ReclaimEmancipatedObjects(); 

            Bid.PoolerTrace(" %d#, Cleared.\n", ObjectID); 
        }

        private Timer CreateCleanupTimer() {
            return (new Timer(new TimerCallback(this.CleanupCallback), null, _cleanupWait, _cleanupWait)); 
        }
 
        private DbConnectionInternal CreateObject(DbConnection owningObject) { 
            DbConnectionInternal newObj = null;
 
            try {
                newObj = _connectionFactory.CreatePooledConnection(owningObject, this, _connectionPoolGroup.ConnectionOptions);
                if (null == newObj) {
                    throw ADP.InternalError(ADP.InternalErrorCode.CreateObjectReturnedNull);    // CreateObject succeeded, but null object 
                }
                if (!newObj.CanBePooled) { 
                    throw ADP.InternalError(ADP.InternalErrorCode.NewObjectCannotBePooled);        // CreateObject succeeded, but non-poolable object 
                }
                newObj.PrePush(null); 

                lock (_objectList) {
                    _objectList.Add(newObj);
                    _totalObjects = _objectList.Count; 
                    PerformanceCounters.NumberOfPooledConnections.Increment();   //
                } 
                Bid.PoolerTrace(" %d#, Connection %d#, Added to pool.\n", ObjectID, newObj.ObjectID); 

                // Reset the error wait: 
                _errorWait = ERROR_WAIT_DEFAULT;
            }
            catch(Exception e)  {
                // 
                if (!ADP.IsCatchableExceptionType(e)) {
                    throw; 
                } 

                ADP.TraceExceptionForCapture(e); 

                newObj = null; // set to null, so we do not return bad new object
                // Failed to create instance
                _resError = e; 
                _waitHandles.ErrorEvent.Set();
                   _errorOccurred = true; 
                _errorTimer = new Timer(new TimerCallback(this.ErrorCallback), null, _errorWait, _errorWait); 

                if (30000 < _errorWait) { 
                    _errorWait = 60000;
                }
                else {
                    _errorWait *= 2; 
                }
                throw; 
            } 
            return newObj;
        } 

        private void DeactivateObject(DbConnectionInternal obj) {
            Bid.PoolerTrace(" %d#, Connection %d#, Deactivating.\n", ObjectID, obj.ObjectID);
 
            obj.DeactivateConnection(); // we presume this operation is safe outside of a lock...
 
            if ((State.Running == _state) && !obj.IsConnectionDoomed) { 
                bool returnToGeneralPool = true;
 
                lock (obj) {
                    // A connection with a delegated transaction cannot currently
                    // be returned to a different customer until the transaction
                    // actually completes, so we send it into Stasis -- the SysTx 
                    // transaction object will ensure that it is owned (not lost),
                    // and it will be certain to put it back into the pool. 
                    if (obj.IsNonPoolableTransactionRoot) { 
                        obj.SetInStasis();
                        returnToGeneralPool = false; 
                    }
                    else {
                        // We must put this connection into the transacted pool
                        // while inside a lock to prevent a race condition with 
                        // the transaction asyncronously completing on a second
                        // thread. 
                        SysTx.Transaction transaction = obj.EnlistedTransaction; 
                        if (null != transaction) {
                            TransactionBegin(transaction);  // Delayed creation of transacted pool 
                            _transactedConnectionPool.PutTransactedObject(transaction, obj);
                            returnToGeneralPool = false;
                        }
                    } 
                }
 
                // Only push the connection into the general pool if we didn't 
                // already push it onto the transacted pool.
                if (returnToGeneralPool) { 
                    PutNewObject(obj);
                }
            }
            else { 
                // the object is not fit for reuse -- just dispose of it.
                DestroyObject(obj); 
                QueuePoolCreateRequest(); 
            }
        } 

        private void DestroyObject(DbConnectionInternal obj) {
            // A connection with a delegated transaction cannot be disposed of
            // until the delegated transaction has actually completed.  Instead, 
            // we simply leave it alone; when the transaction completes, it will
            // come back through PutObjectFromTransactedPool, which will call us 
            // again. 
            if (obj.IsTxRootWaitingForTxEnd) {
                Bid.PoolerTrace(" %d#, Connection %d#, Has Delegated Transaction, waiting to Dispose.\n", ObjectID, obj.ObjectID); 
            }
            else {
                Bid.PoolerTrace(" %d#, Connection %d#, Removing from pool.\n", ObjectID, obj.ObjectID);
 
                bool removed = false;
                lock (_objectList) { 
                    removed = _objectList.Remove(obj); 
                    Debug.Assert(removed, "attempt to DestroyObject not in list");
                    _totalObjects = _objectList.Count; 
                }

                if (removed) {
                    Bid.PoolerTrace(" %d#, Connection %d#, Removed from pool.\n", ObjectID, obj.ObjectID); 
                    PerformanceCounters.NumberOfPooledConnections.Decrement();
                } 
                obj.Dispose(); 

                Bid.PoolerTrace(" %d#, Connection %d#, Disposed.\n", ObjectID, obj.ObjectID); 
                PerformanceCounters.HardDisconnectsPerSecond.Increment();
            }
        }
 
        private void ErrorCallback(Object state) {
            Bid.PoolerTrace(" %d#, Resetting Error handling.\n", ObjectID); 
 
            _errorOccurred = false;
            _waitHandles.ErrorEvent.Reset(); 
            Timer t     = _errorTimer;
            _errorTimer = null;
            if (t != null) {
                t.Dispose(); // Cancel timer request. 
            }
        } 
 
        internal DbConnectionInternal GetConnection(DbConnection owningObject) {
            DbConnectionInternal obj = null; 
            SysTx.Transaction transaction = null;

            PerformanceCounters.SoftConnectsPerSecond.Increment();
 
            if(_state != State.Running) {
                Bid.PoolerTrace(" %d#, DbConnectionInternal State != Running.\n", ObjectID); 
                return null; 
            }
 
            Bid.PoolerTrace(" %d#, Getting connection.\n", ObjectID);
            // If automatic transaction enlistment is required, then we try to
            // get the connection from the transacted connection pool first.
            if (HasTransactionAffinity) { 
                obj = GetFromTransactedPool(out transaction);
            } 
 
            if (null == obj) {
                Interlocked.Increment(ref _waitCount); 
                uint waitHandleCount = 3;
                uint timeout = (uint)CreationTimeout;

                do { 
                    int waitResult = BOGUS_HANDLE;
                    int releaseSemaphoreResult = 0; 
 
                    bool mustRelease = false;
                    RuntimeHelpers.PrepareConstrainedRegions(); 
                    try {
                        _waitHandles.DangerousAddRef(ref mustRelease);

                        // We absolutely must have the value of waitResult set, 
                        // or we may leak the mutex in async abort cases.
                        RuntimeHelpers.PrepareConstrainedRegions(); 
                        try { 
                            Debug.Assert(2 == waitHandleCount || 3 == waitHandleCount, "unexpected waithandle count");
                        } 
                        finally {
                            waitResult = SafeNativeMethods.WaitForMultipleObjectsEx(waitHandleCount, _waitHandles.DangerousGetHandle(), false, timeout, false);
                        }
 
                        // 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 WAIT_TIMEOUT:
                            Bid.PoolerTrace(" %d#, Wait timed out.\n", ObjectID); 
                            Interlocked.Decrement(ref _waitCount);
                            return null; 
 
                        case ERROR_HANDLE:
                            // Throw the error that PoolCreateRequest stashed. 
                            Bid.PoolerTrace(" %d#, Errors are set.\n", ObjectID);
                            Interlocked.Decrement(ref _waitCount);
                            throw _resError;
 
                        case CREATION_HANDLE:
                            Bid.PoolerTrace(" %d#, Creating new connection.\n", ObjectID); 
 
                            try {
                                obj = UserCreateRequest(owningObject); 
                            }
                            catch {
                                if (null == obj) {
                                    Interlocked.Decrement(ref _waitCount); 
                                }
                                throw; 
                            } 
                            finally {
                                // SQLBUDT #386664 - 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"); 
                                        waitHandleCount = 2;
                                    }
                                }
                            } 
                            break;
 
                        case SEMAPHORE_HANDLE: 
                            //
                            //    guaranteed available inventory 
                            //
                            Interlocked.Decrement(ref _waitCount);
                            obj = GetFromGeneralPool();
                            break; 

                        case WAIT_FAILED: 
                            Bid.PoolerTrace(" %d#, Wait failed.\n", ObjectID); 
                            Interlocked.Decrement(ref _waitCount);
                            Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 
                            goto default; // if ThrowExceptionForHR didn't throw for some reason
                        case (WAIT_ABANDONED+SEMAPHORE_HANDLE):
                            Bid.PoolerTrace(" %d#, Semaphore handle abandonded.\n", ObjectID);
                            Interlocked.Decrement(ref _waitCount); 
                            throw new AbandonedMutexException(SEMAPHORE_HANDLE,_waitHandles.PoolSemaphore);
                        case (WAIT_ABANDONED+ERROR_HANDLE): 
                            Bid.PoolerTrace(" %d#, Error handle abandonded.\n", ObjectID); 
                            Interlocked.Decrement(ref _waitCount);
                            throw new AbandonedMutexException(ERROR_HANDLE,_waitHandles.ErrorEvent); 
                        case (WAIT_ABANDONED+CREATION_HANDLE):
                            Bid.PoolerTrace(" %d#, Creation handle abandoned.\n", ObjectID);
                            Interlocked.Decrement(ref _waitCount);
                            throw new AbandonedMutexException(CREATION_HANDLE,_waitHandles.CreationSemaphore); 
                        default:
                            Bid.PoolerTrace(" %d#, WaitForMultipleObjects=%d\n", ObjectID, waitResult); 
                            Interlocked.Decrement(ref _waitCount); 
                            throw ADP.InternalError(ADP.InternalErrorCode.UnexpectedWaitAnyResult);
                        } 
                    }
                    finally {
                        if (CREATION_HANDLE == waitResult) {
                            int result = SafeNativeMethods.ReleaseSemaphore(_waitHandles.CreationHandle.DangerousGetHandle(), 1, IntPtr.Zero); 
                            if (0 == result) { // failure case
                                releaseSemaphoreResult = Marshal.GetHRForLastWin32Error(); 
                            } 
                        }
                        if (mustRelease) { 
                            _waitHandles.DangerousRelease();
                        }
                    }
                    if (0 != releaseSemaphoreResult) { 
                        Marshal.ThrowExceptionForHR(releaseSemaphoreResult); // will only throw if (hresult < 0)
                    } 
                } while (null == obj); 
            }
 
            if (null != obj) {
                lock (obj) {   // Protect against Clear and ReclaimEmancipatedObjects, which call IsEmancipated, which is affected by PrePush and PostPop
                    obj.PostPop(owningObject);
                } 
                try {
                    obj.ActivateConnection(transaction); 
                } 
                catch(SecurityException) {
                    // if Activate throws an exception 
                    // put it back in the pool or have it properly disposed of
                    this.PutObject(obj, owningObject);
                    throw;
                } 
            }
            return(obj); 
        } 

        private DbConnectionInternal GetFromGeneralPool() { 
            DbConnectionInternal obj = null;

            obj = _stackNew.SynchronizedPop();
            if (null == obj) { 
                obj = _stackOld.SynchronizedPop();
            } 
 
            // SQLBUDT #356870 -- When another thread is clearing this pool,
            // it will remove all connections in this pool which causes the 
            // following assert to fire, which really mucks up stress against
            //  checked bits.  The assert is benign, so we're commenting it out.
            //Debug.Assert(obj != null, "GetFromGeneralPool called with nothing in the pool!");
 
            if (null != obj) {
                Bid.PoolerTrace(" %d#, Connection %d#, Popped from general pool.\n", ObjectID, obj.ObjectID); 
                PerformanceCounters.NumberOfFreeConnections.Decrement(); 
            }
            return(obj); 
        }

        private DbConnectionInternal GetFromTransactedPool(out SysTx.Transaction transaction) {
            transaction = ADP.GetCurrentTransaction(); 
            DbConnectionInternal obj = null;
 
            if (null != transaction && null != _transactedConnectionPool) { 
                obj = _transactedConnectionPool.GetTransactedObject(transaction);
 
                if (null != obj) {
                    Bid.PoolerTrace(" %d#, Connection %d#, Popped from transacted pool.\n", ObjectID, obj.ObjectID);
                    PerformanceCounters.NumberOfFreeConnections.Decrement();
                } 
            }
            return obj; 
        } 

        private void PoolCreateRequest(object state) { 
            // called by pooler to ensure pool requests are currently being satisfied -
            // creation mutex has not been obtained

            IntPtr hscp; 

            Bid.PoolerScopeEnter(out hscp, " %d#\n", ObjectID); 
 
            try {
                if (State.Running == _state) { 
                    // Before creating any new objects, reclaim any released objects that were
                    // not closed.
                    ReclaimEmancipatedObjects();
 
                    if (!ErrorOccurred) {
                        if (NeedToReplenish) { 
                            // Check to see if pool was created using integrated security and if so, make 
                            // sure the identity of current user matches that of user that created pool.
                            // If it doesn't match, do not create any objects on the ThreadPool thread, 
                            // since either Open will fail or we will open a object for this pool that does
                            // not belong in this pool.  The side effect of this is that if using integrated
                            // security min pool size cannot be guaranteed.
                            if (UsingIntegrateSecurity && !_identity.Equals(DbConnectionPoolIdentity.GetCurrent())) { 
                                return;
                            } 
                            bool mustRelease = false; 
                            int waitResult = BOGUS_HANDLE;
                            uint timeout = (uint)CreationTimeout; 

                            RuntimeHelpers.PrepareConstrainedRegions();
                            try {
                                _waitHandles.DangerousAddRef(ref mustRelease); 

                                // Obtain creation mutex so we're the only one creating objects 
                                // and we must have the wait result 
                                RuntimeHelpers.PrepareConstrainedRegions();
                                try { } finally { 
                                    waitResult = SafeNativeMethods.WaitForSingleObjectEx(_waitHandles.CreationHandle.DangerousGetHandle(), timeout, false);
                                }
                                if (WAIT_OBJECT_0 == waitResult) {
                                    DbConnectionInternal newObj; 

                                    // Check ErrorOccurred again after obtaining mutex 
                                    if (!ErrorOccurred) { 
                                        while (NeedToReplenish) {
                                            newObj = CreateObject((DbConnection)null); 

                                            // We do not need to check error flag here, since we know if
                                            // CreateObject returned null, we are in error case.
                                            if (null != newObj) { 
                                                PutNewObject(newObj);
                                            } 
                                            else { 
                                                break;
                                            } 
                                        }
                                    }
                                }
                                else if (WAIT_TIMEOUT == waitResult) { 
                                    // do not wait forever and potential block this worker thread
                                    // instead wait for a period of time and just requeue to try again 
                                    QueuePoolCreateRequest(); 
                                }
                                else { 
                                    // trace waitResult and ignore the failure
                                    Bid.PoolerTrace(" %d#, PoolCreateRequest called WaitForSingleObject failed %d", ObjectID, waitResult);
                                }
                            } 
                            catch (Exception e) {
                                // 
                                if (!ADP.IsCatchableExceptionType(e)) { 
                                    throw;
                                } 

                                // Now that CreateObject can throw, we need to catch the exception and discard it.
                                // There is no further action we can take beyond tracing.  The error will be
                                // thrown to the user the next time they request a connection. 
                                Bid.PoolerTrace(" %d#, PoolCreateRequest called CreateConnection which threw an exception: " + e.ToString(), ObjectID);
                            } 
                            finally { 
                                if (WAIT_OBJECT_0 == waitResult) {
                                    // reuse waitResult and ignore its value 
                                    waitResult = SafeNativeMethods.ReleaseSemaphore(_waitHandles.CreationHandle.DangerousGetHandle(), 1, IntPtr.Zero);
                                }
                                if (mustRelease) {
                                    _waitHandles.DangerousRelease(); 
                                }
                            } 
                        } 
                    }
                } 
            }
            finally {
                Bid.ScopeLeave(ref hscp);
            } 
        }
 
        private void ProcessDeactivateQueue(object state) { 
            IntPtr hscp;
 
            Bid.PoolerScopeEnter(out hscp, " %d#\n", ObjectID);

            try {
                object[] deactivateQueue; 
                lock (_deactivateQueue.SyncRoot) {
                    deactivateQueue = _deactivateQueue.ToArray(); 
                    _deactivateQueue.Clear(); 
                }
 
                foreach (DbConnectionInternal obj in deactivateQueue) {
                    PerformanceCounters.NumberOfStasisConnections.Decrement();
                    DeactivateObject(obj);
                } 
            }
            finally { 
                Bid.ScopeLeave(ref hscp); 
            }
        } 

        internal void PutNewObject(DbConnectionInternal obj) {
            Debug.Assert(null != obj,        "why are we adding a null object to the pool?");
            Debug.Assert(obj.CanBePooled,    "non-poolable object in pool"); 

            Bid.PoolerTrace(" %d#, Connection %d#, Pushing to general pool.\n", ObjectID, obj.ObjectID); 
 
            _stackNew.SynchronizedPush(obj);
            _waitHandles.PoolSemaphore.Release(1); 
            PerformanceCounters.NumberOfFreeConnections.Increment();

        }
 
        internal void PutObject(DbConnectionInternal obj, object owningObject) {
            Debug.Assert(null != obj, "null obj?"); 
 
            PerformanceCounters.SoftDisconnectsPerSecond.Increment();
 
            // Once a connection is closing (which is the state that we're in at
            // this point in time) you cannot delegate a transaction to or enlist
            // a transaction in it, so we can correctly presume that if there was
            // not a delegated or enlisted transaction to start with, that there 
            // will not be a delegated or enlisted transaction once we leave the
            // lock. 
 
            lock (obj) {
                // Calling PrePush prevents the object from being reclaimed 
                // once we leave the lock, because it sets _pooledCount such
                // that it won't appear to be out of the pool.  What that
                // means, is that we're now responsible for this connection:
                // it won't get reclaimed if we drop the ball somewhere. 
                obj.PrePush(owningObject);
 
                // 
            }
 
            if (UseDeactivateQueue) {
                // If we're using the DeactivateQueue, we'll just queue it up and
                // be done; all the hard work will be done on the despooler thread.
 
                bool needToQueueWorkItem;
 
                Bid.PoolerTrace(" %d#, Connection %d#, Queueing for deactivation.\n", ObjectID, obj.ObjectID); 
                PerformanceCounters.NumberOfStasisConnections.Increment();
 
                lock (_deactivateQueue.SyncRoot) {
                    needToQueueWorkItem = (0 == _deactivateQueue.Count);
                    _deactivateQueue.Enqueue(obj);
                } 
                if (needToQueueWorkItem) {
                    // Make sure we actually get around to deactivating the object 
                    // and making it available again. 
                    ThreadPool.QueueUserWorkItem(_deactivateCallback, null);
                } 
            }
            else {
                // no deactivate queue -- do the work right now.
                DeactivateObject(obj); 
            }
        } 
 
        internal void PutObjectFromTransactedPool(DbConnectionInternal obj) {
            Debug.Assert(null != obj, "null pooledObject?"); 
            Debug.Assert(!obj.HasEnlistedTransaction, "pooledObject is still enlisted?");

            // called by the transacted connection pool , once it's removed the
            // connection from it's list.  We put the connection back in general 
            // circulation.
 
            // NOTE: there is no locking required here because if we're in this 
            // method, we can safely presume that the caller is the only person
            // that is using the connection, and that all pre-push logic has been 
            // done and all transactions are ended.

            Bid.PoolerTrace(" %d#, Connection %d#, Transaction has ended.\n", ObjectID, obj.ObjectID);
 
            if (_state == State.Running && obj.CanBePooled) {
                PutNewObject(obj); 
            } 
            else {
                DestroyObject(obj); 
                QueuePoolCreateRequest();
            }
        }
 
        private void QueuePoolCreateRequest() {
            if (State.Running == _state) { 
                // Make sure we're at quota by posting a callback to the threadpool. 
                ThreadPool.QueueUserWorkItem(_poolCreateRequest);
            } 
        }

        private bool ReclaimEmancipatedObjects() {
            bool emancipatedObjectFound = false; 

            Bid.PoolerTrace(" %d#\n", ObjectID); 
 
            List reclaimedObjects = new List();
            int count; 

            lock(_objectList) {
                count = _objectList.Count;
 
                for (int i = 0; i < count; ++i) {
                    DbConnectionInternal obj = _objectList[i]; 
 
                    if (null != obj) {
                        bool locked = false; 

                        try {
                            locked = Monitor.TryEnter(obj);
 
                            if (locked) { // avoid race condition with PrePush/PostPop and IsEmancipated
                                if (obj.IsEmancipated) { 
                                    // Inside the lock, we want to do as little 
                                    // as possible, so we simply mark the object
                                    // as being in the pool, but hand it off to 
                                    // an out of pool list to be deactivated,
                                    // etc.
                                    obj.PrePush(null);
                                    reclaimedObjects.Add(obj); 
                                }
                            } 
                        } 
                        finally {
                            if (locked) 
                                Monitor.Exit(obj);
                        }
                    }
                } 
            }
 
            // NOTE: we don't want to call DeactivateObject while we're locked, 
            // because it can make roundtrips to the server and this will block
            // object creation in the pooler.  Instead, we queue things we need 
            // to do up, and process them outside the lock.
            count = reclaimedObjects.Count;

            for (int i = 0; i < count; ++i) { 
                DbConnectionInternal obj = reclaimedObjects[i];
 
                Bid.PoolerTrace(" %d#, Connection %d#, Reclaiming.\n", ObjectID, obj.ObjectID); 
                PerformanceCounters.NumberOfReclaimedConnections.Increment();
 
                emancipatedObjectFound = true;

                // NOTE: it is not possible for us to have a connection that has
                // a delegated transaction at this point, because IsEmancipated 
                // would not have returned true if it did, and when a connection
                // is emancipated, you can't enlist in a transaction (because you 
                // can't get to it to make the call...) 
                DeactivateObject(obj);
            } 
            return emancipatedObjectFound;
        }

        internal void Startup() { 
            Bid.PoolerTrace(" %d#, CleanupWait=%d\n", ObjectID, _cleanupWait);
 
            _cleanupTimer = CreateCleanupTimer(); 
            if (NeedToReplenish) {
                QueuePoolCreateRequest(); 
            }
        }

        internal void Shutdown() { 
            Bid.PoolerTrace(" %d#\n", ObjectID);
 
            _state = State.ShuttingDown; 

            Timer t; // deactivate timer callbacks 

            t = _cleanupTimer;
            _cleanupTimer = null;
            if (null != t) { 
                t.Dispose();
            } 
 
            t = _errorTimer;
            _errorTimer = null; 
            if (null != t) {
                t.Dispose();
            }
        } 

        internal void TransactionBegin(SysTx.Transaction transaction) { 
            TransactedConnectionPool transactedConnectionPool = _transactedConnectionPool; 
            if (null != transactedConnectionPool) {
                transactedConnectionPool.TransactionBegin(transaction); 
            }
        }

        internal void TransactionEnded(SysTx.Transaction transaction, DbConnectionInternal transactedObject) { 
            Debug.Assert(null != transaction, "null transaction?");
            Debug.Assert(null != transactedObject, "null transactedObject?"); 
            // Note: connection may still be associated with transaction due to Explicit Unbinding requirement. 

            Bid.PoolerTrace(" %d#, Transaction %d#, Connection %d#, Transaction Completed\n", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID); 

            // called by the internal connection when it get's told that the
            // transaction is completed.  We tell the transacted pool to remove
            // the connection from it's list, then we put the connection back in 
            // general circulation.
 
            TransactedConnectionPool transactedConnectionPool = _transactedConnectionPool; 
            if (null != transactedConnectionPool) {
                transactedConnectionPool.TransactionEnded(transaction, transactedObject); 
            }
        }

        private DbConnectionInternal UserCreateRequest(DbConnection owningObject) { 
            // called by user when they were not able to obtain a free object but
            // instead obtained creation mutex 
 
            DbConnectionInternal obj = null;
            if (ErrorOccurred) { 
               throw _resError;
            }
            else {
                 if ((Count < MaxPoolSize) || (0 == MaxPoolSize)) { 
                    // If we have an odd number of total objects, reclaim any dead objects.
                    // If we did not find any objects to reclaim, create a new one. 
 
                    //
                     if ((Count & 0x1) == 0x1 || !ReclaimEmancipatedObjects()) 
                        obj = CreateObject(owningObject);
                }
                return obj;
            } 
        }
 
        private class DbConnectionInternalListStack { 
            private DbConnectionInternal _stack;
#if DEBUG 
            private int _version;
            private int _count;
#endif
            internal DbConnectionInternalListStack() { 
            }
 
            internal int Count { 
                get {
                    int count = 0; 
                    lock(this) {
                        for(DbConnectionInternal x = _stack; null != x; x = x.NextPooledObject) {
                            ++count;
                        } 
                    }
#if DEBUG 
                    Debug.Assert(count == _count, "count is corrupt"); 
#endif
                    return count; 
                }
            }

            internal DbConnectionInternal SynchronizedPop() { 
                DbConnectionInternal value;
                lock(this) { 
                    value = _stack; 
                    if (null != value) {
                        _stack = value.NextPooledObject; 
                        value.NextPooledObject = null;
#if DEBUG
                        _version++;
                        _count--; 
#endif
                    } 
#if DEBUG 
                    Debug.Assert((null != value || 0 == _count) && (0 <= _count), "broken SynchronizedPop");
#endif 
                }
                return value;
            }
 
            internal void SynchronizedPush(DbConnectionInternal value) {
                Debug.Assert(null != value, "pushing null value"); 
                lock(this) { 
#if DEBUG
                    Debug.Assert(null == value.NextPooledObject, "pushing value with non-null NextPooledObject"); 
                    int index = 0;
                    for(DbConnectionInternal x = _stack; null != x; x = x.NextPooledObject, ++index) {
                        Debug.Assert(x != value, "double push: connection already in stack");
                    } 
                    Debug.Assert(_count == index, "SynchronizedPush count is corrupt");
#endif 
                    value.NextPooledObject = _stack; 
                    _stack = value;
#if DEBUG 
                    _version++;
                    _count++;
#endif
                } 
            }
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK