|
|
|
@ -4,42 +4,33 @@ |
|
|
|
using System; |
|
|
|
using System.Runtime.InteropServices; |
|
|
|
using System.Threading; |
|
|
|
using SixLabors.ImageSharp.Diagnostics; |
|
|
|
|
|
|
|
namespace SixLabors.ImageSharp.Memory.Internals |
|
|
|
{ |
|
|
|
/// <summary>
|
|
|
|
/// Implements reference counting lifetime guard mechanism similar to the one provided by <see cref="SafeHandle"/>,
|
|
|
|
/// but without the restriction of the guarded object being a handle.
|
|
|
|
/// Implements reference counting lifetime guard mechanism for memory resources
|
|
|
|
/// also maintaining the current value of <see cref="MemoryInfo.TotalUndisposedAllocationCount"/>.
|
|
|
|
/// </summary>
|
|
|
|
internal abstract class RefCountedLifetimeGuard : IDisposable |
|
|
|
internal abstract class RefCountedMemoryLifetimeGuard : IDisposable |
|
|
|
{ |
|
|
|
private int refCount = 1; |
|
|
|
private int disposed; |
|
|
|
private int released; |
|
|
|
|
|
|
|
~RefCountedLifetimeGuard() |
|
|
|
public RefCountedMemoryLifetimeGuard() => MemoryDiagnostics.IncrementTotalUndisposedAllocationCount(); |
|
|
|
|
|
|
|
~RefCountedMemoryLifetimeGuard() |
|
|
|
{ |
|
|
|
Interlocked.Exchange(ref this.disposed, 1); |
|
|
|
this.ReleaseRef(); |
|
|
|
this.ReleaseRef(true); |
|
|
|
} |
|
|
|
|
|
|
|
public bool IsDisposed => this.disposed == 1; |
|
|
|
|
|
|
|
public void AddRef() => Interlocked.Increment(ref this.refCount); |
|
|
|
|
|
|
|
public void ReleaseRef() |
|
|
|
{ |
|
|
|
Interlocked.Decrement(ref this.refCount); |
|
|
|
if (this.refCount == 0) |
|
|
|
{ |
|
|
|
int wasReleased = Interlocked.Exchange(ref this.released, 1); |
|
|
|
|
|
|
|
if (wasReleased == 0) |
|
|
|
{ |
|
|
|
this.Release(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
public void ReleaseRef() => this.ReleaseRef(false); |
|
|
|
|
|
|
|
public void Dispose() |
|
|
|
{ |
|
|
|
@ -52,5 +43,24 @@ namespace SixLabors.ImageSharp.Memory.Internals |
|
|
|
} |
|
|
|
|
|
|
|
protected abstract void Release(); |
|
|
|
|
|
|
|
private void ReleaseRef(bool finalizing) |
|
|
|
{ |
|
|
|
Interlocked.Decrement(ref this.refCount); |
|
|
|
if (this.refCount == 0) |
|
|
|
{ |
|
|
|
int wasReleased = Interlocked.Exchange(ref this.released, 1); |
|
|
|
|
|
|
|
if (wasReleased == 0) |
|
|
|
{ |
|
|
|
if (!finalizing) |
|
|
|
{ |
|
|
|
MemoryDiagnostics.DecrementTotalUndisposedAllocationCount(); |
|
|
|
} |
|
|
|
|
|
|
|
this.Release(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |