Ejemplo n.º 1
0
        // Funnel all delegates through here to ensure proper procedure for getting and releasing locks.
        private bool Execute(TKey key, LockType type, Action <ReaderWriterLockSlim> closure, int?millisecondsTimeout = null, bool throwsOnTimeout = false)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }
            if (closure == null)
            {
                throw new ArgumentNullException(nameof(closure));
            }
            ReaderWriterLockSlimExensions.ValidateMillisecondsTimeout(millisecondsTimeout);
            Contract.EndContractBlock();

            var context = ContextPool.Take();

            var rwlock = GetLock(key, type, context, millisecondsTimeout, throwsOnTimeout);

            if (rwlock == null)
            {
                return(false);
            }

            try
            {
                closure(rwlock.Lock);
            }
            finally
            {
                try
                {
                    ReleaseLock(rwlock.Lock, type);
                    rwlock.Clear(context);
                    ContextPool.Give(context);
                }
                catch (Exception ex)
                {
                    ex.WriteToDebug();
                    // The above cannot fail or dire concequences...
                    Debugger.Break();
                    throw;
                }
            }
            return(true);
        }
Ejemplo n.º 2
0
        private bool AcquireLock(ReaderWriterLockSlim target, LockType type, int?millisecondsTimeout = null, bool throwsOnTimeout = false)
        {
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }
            ReaderWriterLockSlimExensions.ValidateMillisecondsTimeout(millisecondsTimeout);
            Contract.EndContractBlock();

            switch (type)
            {
            case LockType.Read:
                return(target.EnterReadLock(millisecondsTimeout, throwsOnTimeout));

            case LockType.ReadUpgradeable:
                return(target.EnterUpgradeableReadLock(millisecondsTimeout, throwsOnTimeout));

            case LockType.Write:
                return(target.EnterWriteLock(millisecondsTimeout, throwsOnTimeout));
            }

            return(false);
        }
Ejemplo n.º 3
0
        private ReaderWriterLockTracker GetLock(TKey key, LockType type, object context, int?millisecondsTimeout = null, bool throwsOnTimeout = false)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            ReaderWriterLockSlimExensions.ValidateMillisecondsTimeout(millisecondsTimeout);
            Contract.EndContractBlock();

            if (IsDisposed)
            {
                return(null);
            }

            // Need to be able to enter a lock before releasing access in order to prevent removal...
            var r = CleanupManager.ReadValue(
                () =>
            {
                // It is possible that a read could be acquired while disposing just before the dispose.
                if (IsDisposed)
                {
                    return(null);
                }

                // Get a tracker...
                ReaderWriterLockTracker result;
                {
                    // Compare the tracker retrieved with the one created...
                    ReaderWriterLockTracker created = null;
                    do
                    {
                        result = Locks.GetOrAdd(key, k => created = LockPool.Take());
                    }
                    // Safeguard against rare case of when a disposed tracker is retained via an exception (possibly?). :(
                    while (!IsDisposed && result.IsDisposed);


                    // If the one created is not the one retrieved, go ahead and add it to the pool so it doesn't go to waste.
                    if (created != null && created != result)
                    {
                        if (IsDisposed)
                        {
                            created.Dispose();
                        }
                        else
                        {
                            LockPool.Give(created);
                        }
                    }

                    // This should never get out of sync, but just in case...
                    var rlock = result.Lock;
                    if (rlock == null || result.IsDisposed)
                    {
                        Debug.Fail("A lock tracker was retained after it was disposed.");
                        return(null);
                    }
                    else if (Debugger.IsAttached && rlock.RecursionPolicy == LockRecursionPolicy.NoRecursion)
                    {
                        if (rlock.IsWriteLockHeld && type == LockType.Read)
                        {
                            Debugger.Break();                                     //
                        }
                    }
                }

                // Quick check to avoid further processes...
                if (IsDisposed)
                {
                    return(null);
                }

                var lockHeld = false;
                if (!result.Reserve(context))
                {
                    return(null);
                }
                try
                {
                    // result.Lock will only be null if the tracker has been disposed.
                    lockHeld = AcquireLock(result.Lock, type, millisecondsTimeout, throwsOnTimeout);
                }
                catch (LockRecursionException lrex)
                {
                    lrex.WriteToDebug();
                    Debugger.Break();                             // Need to be able to track down source.
                    throw;
                }
                finally
                {
                    if (!lockHeld)
                    {
                        result.Clear(context);
                    }
                }

                return(lockHeld ? result : null);
            });

            // In the rare case that a dispose could be initiated during this ReadValue:
            // We need to not propagate locking...
            if (r == null || !IsDisposed)
            {
                return(r);
            }
            ReleaseLock(r.Lock, type);
            r.Clear(context);

            return(null);
        }