예제 #1
0
        /// <summary>
        /// Process the non-dispose. Used when <see cref="nonDisposable"/> is true (singleton instances).
        ///
        /// This may be called from <see cref="Dispose"/> or from the dispose of the last
        /// belate handle (After <see cref="Dispose"/> has been called aswell).
        ///
        /// Only one thread may process the dispose. Returns state back to 0.
        ///
        /// Unattaches all disposables, disposes them, and calls <see cref="InnerDispose(ref StructList4{Exception})"/>.
        /// Does not set state
        /// </summary>
        /// <exception cref="AggregateException">thrown if disposing threw errors</exception>
        protected virtual void ProcessNonDispose()
        {
            // Revert state
            Interlocked.CompareExchange(ref disposing, 0L, 1L);

            // Extract snapshot, clear array
            StructList2 <IDisposable> toDispose = default;

            lock (m_disposelist_lock) { toDispose = disposeList; disposeList = default; }

            // Captured errors
            StructList4 <Exception> disposeErrors = new StructList4 <Exception>();

            // Dispose disposables
            DisposeList.DisposeAndCapture(ref toDispose, ref disposeErrors);

            // Call InnerDispose(). Capture errors to compose it with others.
            try
            {
                InnerDispose(ref disposeErrors);
            }
            catch (Exception e)
            {
                // Capture error
                disposeErrors.Add(e);
            }

            // Throw captured errors
            if (disposeErrors.Count > 0)
            {
                throw new AggregateException(disposeErrors);
            }
        }
예제 #2
0
        /// <summary>
        /// Add <paramref name="disposableObjects"/> to be disposed with the object.
        /// </summary>
        /// <param name="disposableObjects"></param>
        /// <returns></returns>
        bool IDisposeList.AddDisposables(IEnumerable disposableObjects)
        {
            // Argument error
            if (disposableObjects == null)
            {
                throw new ArgumentNullException(nameof(disposableObjects));
            }
            // Parent is disposed/ing
            if (IsDisposing)
            {
                // Captured errors
                StructList4 <Exception> disposeErrors = new StructList4 <Exception>();
                // Dispose now
                DisposeList.DisposeAndCapture(disposableObjects, ref disposeErrors);
                // Throw captured errors
                if (disposeErrors.Count > 0)
                {
                    throw new AggregateException(disposeErrors);
                }
                return(false);
            }

            // Add to list
            lock (m_disposelist_lock)
                foreach (Object d in disposableObjects)
                {
                    if (d is IDisposable disposable)
                    {
                        disposeList.Add(disposable);
                    }
                }

            // Check parent again
            if (IsDisposing)
            {
                // Captured errors
                StructList4 <Exception> disposeErrors = new StructList4 <Exception>();
                // Dispose now
                DisposeList.DisposeAndCapture(disposableObjects, ref disposeErrors);
                // Remove
                lock (m_disposelist_lock) foreach (object d in disposableObjects)
                    {
                        if (d is IDisposable disp)
                        {
                            disposeList.Remove(disp);
                        }
                    }
                // Throw captured errors
                if (disposeErrors.Count > 0)
                {
                    throw new AggregateException(disposeErrors);
                }
                return(false);
            }

            // OK
            return(true);
        }
예제 #3
0
        /// <summary>
        /// Process the actual dispose. This may be called from <see cref="Dispose"/> or from the dispose of the last
        /// belate handle (After <see cref="Dispose"/> has been called aswell).
        ///
        /// Only one thread may process the dispose.
        /// Sets state to 2, and then 3.
        ///
        /// Unattaches all disposables, disposes them, and calls <see cref="InnerDispose(ref StructList4{Exception})"/>.
        /// </summary>
        /// <exception cref="AggregateException">thrown if disposing threw errors</exception>
        protected virtual void ProcessDispose()
        {
            // Set state IsDisposing=2, but let only one thread continue.
            bool thisThreadChangedStateToIsDispose = (Interlocked.CompareExchange(ref disposing, 2L, 0L) == 0L) || (Interlocked.CompareExchange(ref disposing, 2L, 1L) == 1L);

            // Not for this thread.
            if (!thisThreadChangedStateToIsDispose)
            {
                return;
            }

            // Extract snapshot, clear array
            StructList2 <IDisposable> toDispose = default;

            lock (m_disposelist_lock) { toDispose = disposeList; disposeList = default; }

            // Captured errors
            StructList4 <Exception> disposeErrors = new StructList4 <Exception>();

            // Dispose disposables
            DisposeList.DisposeAndCapture(ref toDispose, ref disposeErrors);

            // Call InnerDispose(). Capture errors to compose it with others.
            try
            {
                InnerDispose(ref disposeErrors);
            }
            catch (Exception e)
            {
                // Capture error
                disposeErrors.Add(e);
            }

            // Is disposed
            Interlocked.CompareExchange(ref disposing, 3L, 2L);

            // Throw captured errors
            if (disposeErrors.Count > 0)
            {
                throw new AggregateException(disposeErrors);
            }
        }
예제 #4
0
            public void Dispose()
            {
                // Only one thread can dispose
                DisposeList _parent = Interlocked.CompareExchange(ref parent, null, parent);

                // Handle has already been disposed
                if (_parent == null)
                {
                    return;
                }
                // Should dispose be started
                bool processDispose = false;

                // Decrement handle count
                lock (_parent.m_disposelist_lock)
                {
                    int newCount = --_parent.belateHandleCount;
                    // Is not the handle.
                    if (newCount > 0)
                    {
                        return;
                    }
                    // Check Dispose() has been called when counter goes to 0
                    processDispose = _parent.IsDisposeCalled;
                }
                // Start dispose
                if (processDispose)
                {
                    if (_parent.nonDisposable)
                    {
                        _parent.ProcessNonDispose();
                    }
                    else
                    {
                        _parent.ProcessDispose();
                    }
                }
            }
예제 #5
0
 public BelateHandle(DisposeList parent)
 {
     this.parent = parent;
 }