From 288f6dc1087470a5c7840b4bd26ffce2f7afc067 Mon Sep 17 00:00:00 2001 From: Kevin Peizner Date: Wed, 17 Feb 2021 22:25:00 -0800 Subject: [PATCH 1/8] Fix Finalize Dispose pattern in NngDialer class The NngDialer.NativeNngStruct is an unmanaged resource and therefore needs to always be cleaned up in the protected virtual void Dispose(bool) method. https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#the-disposebool-method-overload Also, since this class contains an unmanaged resource a finalizer must also be provided. https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#implement-the-dispose-pattern --- nng.NET/Dialer.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/nng.NET/Dialer.cs b/nng.NET/Dialer.cs index f384c37..05259f4 100644 --- a/nng.NET/Dialer.cs +++ b/nng.NET/Dialer.cs @@ -82,12 +82,19 @@ protected virtual void Dispose(bool disposing) { if (disposed) return; + if (disposing) { - int _ = nng_dialer_close(NativeNngStruct); + // No managed resources to dispose } + + int _ = nng_dialer_close(NativeNngStruct); + disposed = true; } + + ~NngDialer() => Dispose(false); + bool disposed = false; #endregion From 2a9a8f655b957aad6fc75683cd5d6caebe862d23 Mon Sep 17 00:00:00 2001 From: Kevin Peizner Date: Wed, 17 Feb 2021 22:59:54 -0800 Subject: [PATCH 2/8] Fix Finalize Dispose pattern in NngSocket class The NngSocket.NativeNngStruct is an unmanaged resource and therefore needs to always be cleaned up in the protected virtual void Dispose(bool) method. https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#the-disposebool-method-overload Also, since this class contains an unmanaged resource a finalizer must also be provided. https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#implement-the-dispose-pattern --- nng.NET/Socket.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/nng.NET/Socket.cs b/nng.NET/Socket.cs index b80fdea..8cdeefa 100644 --- a/nng.NET/Socket.cs +++ b/nng.NET/Socket.cs @@ -175,12 +175,19 @@ protected virtual void Dispose(bool disposing) { if (disposed) return; + if (disposing) { - int _ = nng_close(NativeNngStruct); + // No managed resources to dispose } + + int _ = nng_close(NativeNngStruct); + disposed = true; } + + ~NngSocket() => Dispose(false); + bool disposed = false; #endregion } From 752db9c3bb72ddb106e576d43391f63d99d290c0 Mon Sep 17 00:00:00 2001 From: Kevin Peizner Date: Wed, 17 Feb 2021 23:05:27 -0800 Subject: [PATCH 3/8] Fix Finalize Dispose pattern in NngListener class The NngDialer.NativeNngStruct is an unmanaged resource and therefore needs to always be cleaned up in the protected virtual void Dispose(bool) method. https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#the-disposebool-method-overload Also, since this class contains an unmanaged resource a finalizer must also be provided. https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#implement-the-dispose-pattern --- nng.NET/Listener.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/nng.NET/Listener.cs b/nng.NET/Listener.cs index 5249235..76ca7c9 100644 --- a/nng.NET/Listener.cs +++ b/nng.NET/Listener.cs @@ -84,12 +84,19 @@ protected virtual void Dispose(bool disposing) { if (disposed) return; + if (disposing) { - int _ = nng_listener_close(NativeNngStruct); + // No managed resources to dispose } + + int _ = nng_listener_close(NativeNngStruct); + disposed = true; } + + ~NngListener() => Dispose(false); + bool disposed = false; #endregion From 642c9cf94700bbdabb649e7dcc2147eae1f750e5 Mon Sep 17 00:00:00 2001 From: Kevin Peizner Date: Wed, 17 Feb 2021 23:09:13 -0800 Subject: [PATCH 4/8] Fix Finalize Dispose pattern in NngAlloc class The NngAlloc.Ptr is an unmanaged resource and therefore needs to always be cleaned up in the protected virtual void Dispose(bool) method. https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#the-disposebool-method-overload Also, since this class contains an unmanaged resource a finalizer must also be provided. https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#implement-the-dispose-pattern --- nng.NET/Memory.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/nng.NET/Memory.cs b/nng.NET/Memory.cs index 83727c4..ed5222f 100644 --- a/nng.NET/Memory.cs +++ b/nng.NET/Memory.cs @@ -40,7 +40,7 @@ public void Take() Ptr = default; Length = default; } - + #region IDisposable public void Dispose() { @@ -52,13 +52,20 @@ protected virtual void Dispose(bool disposing) { if (disposed) return; + if (disposing) { - if (Ptr != IntPtr.Zero) - nng_free(Ptr, Length); + // No managed resources to dispose } + + if (Ptr != IntPtr.Zero) + nng_free(Ptr, Length); + disposed = true; } + + ~NngAlloc() => Dispose(false); + bool disposed = false; #endregion } From 3210a7383f472b126214095604d2ba1fa70f8dd4 Mon Sep 17 00:00:00 2001 From: Kevin Peizner Date: Wed, 17 Feb 2021 23:24:26 -0800 Subject: [PATCH 5/8] Fix Finalize Dispose pattern in NngCtx class The NngCtx.NativeNngStruct is an unmanaged resource and therefore needs to always be cleaned up in the protected virtual void Dispose(bool) method. https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#the-disposebool-method-overload Also, since this class contains an unmanaged resource a finalizer must also be provided. https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#implement-the-dispose-pattern --- nng.NET/AsyncContext.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/nng.NET/AsyncContext.cs b/nng.NET/AsyncContext.cs index 8894a8d..44c672d 100644 --- a/nng.NET/AsyncContext.cs +++ b/nng.NET/AsyncContext.cs @@ -253,12 +253,19 @@ protected virtual void Dispose(bool disposing) { if (disposed) return; + if (disposing) { - var _ = nng_ctx_close(NativeNngStruct); + // No managed resources to dispose } + + var _ = nng_ctx_close(NativeNngStruct); + disposed = true; } + + ~NngCtx() => Dispose(false); + bool disposed = false; #endregion } From 4290bb43a7558fa4e24f46bb562c4047a45eb078 Mon Sep 17 00:00:00 2001 From: Kevin Peizner Date: Wed, 17 Feb 2021 23:54:49 -0800 Subject: [PATCH 6/8] Fixup Finalize Dispose pattern in AsyncBase Managed objects should be conditionally disposed based on whether or not cleanup is deterministic or not. https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#implement-the-dispose-pattern --- nng.NET/AsyncContext.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/nng.NET/AsyncContext.cs b/nng.NET/AsyncContext.cs index 44c672d..4b7da11 100644 --- a/nng.NET/AsyncContext.cs +++ b/nng.NET/AsyncContext.cs @@ -174,10 +174,24 @@ protected void HandleFailedSend() protected object sync = new object(); #region IDisposable - public void Dispose() + public void Dispose() => Dispose(true); + + protected virtual void Dispose(bool disposing) { - Aio?.Dispose(); + if (disposed) + return; + + if (disposing) + { + Aio?.Dispose(); + } + + // No unmanaged resources to cleanup + + disposed = true; } + + bool disposed = false; #endregion } From 39329e3e86d43270f7941e1da4fcb2d9d4e07195 Mon Sep 17 00:00:00 2001 From: Kevin Peizner Date: Thu, 18 Feb 2021 00:03:50 -0800 Subject: [PATCH 7/8] Fix Finalize Dispose pattern in NngStat class Moved Finalize Dispose pattern from StatRoot class into its base class NngStat. The NngStat.NativeNngStruct is an unmanaged resource and therefore needs to always be cleaned up in the protected virtual void Dispose(bool) method. https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#the-disposebool-method-overload Also, since this class contains an unmanaged resource a finalizer must also be provided. https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#implement-the-dispose-pattern This also ensures that NngStat.NativeNngStruct is appropriately cleaned up in StatChild as well. --- nng.NET/Stats.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/nng.NET/Stats.cs b/nng.NET/Stats.cs index b9f0f1e..ca21e54 100644 --- a/nng.NET/Stats.cs +++ b/nng.NET/Stats.cs @@ -35,10 +35,7 @@ public static NngResult GetStatSnapshot() var res = nng_stats_get(out nng_stat statsp); return NngResult.OkThen(res, () => new StatRoot { NativeNngStruct = statsp }); } - } - public class StatRoot : NngStat, IStatRoot - { #region IDisposable public void Dispose() { @@ -52,14 +49,23 @@ protected virtual void Dispose(bool disposing) return; if (disposing) { - nng_stats_free(NativeNngStruct); + // No managed resources to dispose } + nng_stats_free(NativeNngStruct); disposed = true; } + + ~NngStat() => Dispose(false); + bool disposed = false; #endregion } + public class StatRoot : NngStat, IStatRoot + { + + } + public class StatChild : NngStat, IStatChild { public static IStatChild Create(nng_stat stat) From 8f1583a33586875140bbf3648ac72fc8c4aeb2f2 Mon Sep 17 00:00:00 2001 From: Kevin Peizner Date: Thu, 18 Feb 2021 00:14:36 -0800 Subject: [PATCH 8/8] Fix Finalize Dispose pattern in NngString class The NngString.Ptr is an unmanaged resource and therefore needs to always be cleaned up in the protected virtual void Dispose(bool) method. https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#the-disposebool-method-overload Also, since this class contains an unmanaged resource a finalizer must also be provided. https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#implement-the-dispose-pattern --- nng.NET/String.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nng.NET/String.cs b/nng.NET/String.cs index a67f496..a37f934 100644 --- a/nng.NET/String.cs +++ b/nng.NET/String.cs @@ -40,11 +40,13 @@ protected virtual void Dispose(bool disposing) return; if (disposing) { - if (Ptr != IntPtr.Zero) - nng_strfree(Ptr); + // No managed resources to dispose } + if (Ptr != IntPtr.Zero) + nng_strfree(Ptr); disposed = true; } + ~NngString() => Dispose(false); bool disposed = false; #endregion }