From b23cc54491f788d2fe842ae02fa441419b83a204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Tue, 20 Aug 2019 19:39:51 +0200 Subject: [PATCH] Troubleshooting EmbargoServer TC --- Capnp.Net.Runtime/Rpc/Skeleton.cs | 50 +++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/Capnp.Net.Runtime/Rpc/Skeleton.cs b/Capnp.Net.Runtime/Rpc/Skeleton.cs index 9bbc793..283ce5f 100644 --- a/Capnp.Net.Runtime/Rpc/Skeleton.cs +++ b/Capnp.Net.Runtime/Rpc/Skeleton.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using System; +using System.Diagnostics; using System.Runtime.CompilerServices; using System.Text; using System.Threading; @@ -28,6 +29,10 @@ namespace Capnp.Rpc } } +#if DEBUG + const int NoDisposeFlag = 0x4000000; +#endif + static readonly ConditionalWeakTable _implMap = new ConditionalWeakTable(); @@ -58,6 +63,29 @@ namespace Capnp.Rpc return new SkeletonRelinquisher(GetOrCreateSkeleton(impl, true)); } +#if DEBUG + /// + /// This DEBUG-only diagnostic method states that the Skeleton corresponding to a given capability is not expected to + /// be disposed until the next call to EndAssertNotDisposed(). + /// + /// Capability interface + /// Capability implementation + public static void BeginAssertNotDisposed(T impl) where T : class + { + GetOrCreateSkeleton(impl, false).BeginAssertNotDisposed(); + } + + /// + /// This DEBUG-only diagnostic method ends a non-disposal period started with BeginAssertNotDisposed. + /// + /// Capability interface + /// Capability implementation + public static void EndAssertNotDisposed(T impl) where T : class + { + GetOrCreateSkeleton(impl, false).EndAssertNotDisposed(); + } +#endif + int _refCount = 0; /// @@ -75,11 +103,33 @@ namespace Capnp.Rpc Interlocked.Increment(ref _refCount); } +#if DEBUG + internal void BeginAssertNotDisposed() + { + if ((Interlocked.Add(ref _refCount, NoDisposeFlag) & NoDisposeFlag) == 0) + { + throw new InvalidOperationException("Flag already set. State is now broken."); + } + } + internal void EndAssertNotDisposed() + { + if ((Interlocked.Add(ref _refCount, -NoDisposeFlag) & NoDisposeFlag) != 0) + { + throw new InvalidOperationException("Flag already cleared. State is now broken."); + } + } +#endif + internal void Relinquish() { int count = Interlocked.Decrement(ref _refCount); + if (0 == count) { +#if DEBUG + Debug.Assert((_refCount & NoDisposeFlag) == 0, "Skeleton disposal not expected in this state"); +#endif + Dispose(true); GC.SuppressFinalize(this); }