public void Close() { if (!Check()) { throw new FaultException(); } if (m_type == MsgType.Pool) { // if not shared or reference counter drop to zero if ((m_flags & MsgFlags.Shared) == 0 || m_atomicCounter.Decrement() == 0) { BufferPool.Return(m_data); } m_atomicCounter.Dispose(); m_atomicCounter = null; } m_data = null; // Make the message invalid. m_type = MsgType.Invalid; }
public void CouldDispose() { var counter = 0; Assert.IsFalse(AtomicCounter.GetIsDisposed(ref counter)); Assert.AreEqual(1, AtomicCounter.Increment(ref counter)); Assert.AreEqual(2, AtomicCounter.Increment(ref counter)); Assert.Throws <InvalidOperationException>(() => { AtomicCounter.Dispose(ref counter); }); Assert.AreEqual(1, AtomicCounter.Decrement(ref counter)); Assert.AreEqual(0, AtomicCounter.DecrementIfOne(ref counter)); Assert.IsFalse(AtomicCounter.GetIsDisposed(ref counter)); AtomicCounter.Dispose(ref counter); Assert.IsTrue(AtomicCounter.GetIsDisposed(ref counter)); }
private DataBlock() { AtomicCounter.Dispose(ref _refCount); }
public void Dispose(bool disposing) { if (!_isSharedMemory) { DoDispose(); } else { lock (this) { DoDispose(); } } void DoDispose() { if (!disposing) { // Cache has a weak reference, so finalizer could start running while a handle is still in the cache // As if _rc was 1 and we called DecrementIfOne - if successful, no resurrect is possible // because Retain uses IncrementIfRetained. var current = Volatile.Read(ref _rc); var existing = Interlocked.CompareExchange(ref _rc, 0, current); if (existing != current) { // Resurrected while we tried to set rc to zero. // What if rc was wrong and not 1? At some point all new users will // dispose the proxy and it will be in the cache with // positive rc but without GC root, then it will be // collected and finalized and will return to this // place where we will try to set rc to 0 again. // TODO trace this condition, it indicates dropped proxies // From user code it could be possible only when manually using cursors // and forgetting to dispose them, so all blame is on users, but we should not fail. ThrowHelper.AssertFailFast(existing > 1, "existing > 1 when resurrected"); return; } } else { var remaining = AtomicCounter.Decrement(ref _rc); if (remaining > 1) { return; } if (AtomicCounter.DecrementIfOne(ref _rc) != 0) { return; } } ThrowHelper.AssertFailFast(_rc == 0, "_rc must be 0 to proceed with proxy disposal"); try { // remove self from cache _cache._blocks.TryRemove(_key, out var handle); if (handle.IsAllocated) { handle.Free(); } } finally { // If we are shutting down, e.g. unhandled exception in other threads // increase the chances we do release shared memory ref. #pragma warning disable 618 // ReSharper disable once InconsistentlySynchronizedField Block.DisposeFree(); #pragma warning restore 618 } // Do not pool finalized objects. // TODO (review) proxy does not have ref type fields, // probably could add to pool without thinking about GC/finalization order. // However, this case should be very rare (e.g. unhandled exception) // and we care about releasing RC of shared memory above all. if (disposing) { GC.SuppressFinalize(this); // ReSharper disable once InconsistentlySynchronizedField Block = default; _key = default; AtomicCounter.Dispose(ref _rc); _isSharedMemory = default; } } }