/// <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); } }
/// <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); }
/// <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); } }
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(); } } }
public BelateHandle(DisposeList parent) { this.parent = parent; }