diff --git a/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj b/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj
index 6f81750..b7675b9 100644
--- a/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj
+++ b/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj
@@ -29,7 +29,7 @@
- DebugFinalizers
+
diff --git a/Capnp.Net.Runtime/DeserializerState.cs b/Capnp.Net.Runtime/DeserializerState.cs
index 702176c..735ae7e 100644
--- a/Capnp.Net.Runtime/DeserializerState.cs
+++ b/Capnp.Net.Runtime/DeserializerState.cs
@@ -636,9 +636,6 @@ namespace Capnp
///
/// Capability interface
/// index within this struct's pointer table
- /// debugging aid
- /// debugging aid
- /// debugging aid
/// capability instance or null if pointer was null
/// negative index
/// state does not represent a struct, invalid pointer,
@@ -685,15 +682,19 @@ namespace Capnp
return (Rpc.CapabilityReflection.CreateProxy(Caps[(int)CapabilityIndex]) as T)!;
}
+ ///
+ /// Releases the capability table
+ ///
public void Dispose()
{
if (Caps != null && !_disposed)
{
foreach (var cap in Caps)
{
- cap?.Release(false);
+ cap?.Release();
}
+ Caps = null;
_disposed = true;
}
}
diff --git a/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs b/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs
index 6e10a58..4edf578 100644
--- a/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs
+++ b/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs
@@ -251,9 +251,6 @@ namespace Capnp.Rpc
///
/// Capability interface. Must be annotated with .
/// low-level capability
- /// debugging aid
- /// debugging aid
- /// debugging aid
/// The Proxy instance which implements .
/// is null.
/// did not qualify as capability interface.
diff --git a/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs b/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs
index 452bcd3..3faa492 100644
--- a/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs
+++ b/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs
@@ -20,11 +20,7 @@ namespace Capnp.Rpc
internal abstract void Unfreeze();
internal abstract void AddRef();
- internal abstract void Release(
- bool keepAlive,
- [System.Runtime.CompilerServices.CallerMemberName] string methodName = "",
- [System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
- [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0);
+ internal abstract void Release();
#if DebugFinalizers
internal Proxy? OwningProxy { get; set; }
diff --git a/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs b/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs
index 6fc1788..729b34d 100644
--- a/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs
+++ b/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs
@@ -24,6 +24,12 @@ namespace Capnp.Rpc
/// Pipelined low-level capability
ConsumedCapability? Access(MemberAccessPath access);
+ ///
+ ///
+ ///
+ /// Creates a low-level capability for promise pipelining.
+ /// Task returning the proxy whose ownership will be taken over
+ ///
ConsumedCapability? Access(MemberAccessPath access, Task proxyTask);
}
}
\ No newline at end of file
diff --git a/Capnp.Net.Runtime/Rpc/Impatient.cs b/Capnp.Net.Runtime/Rpc/Impatient.cs
index 1e621b5..7b2c7b3 100644
--- a/Capnp.Net.Runtime/Rpc/Impatient.cs
+++ b/Capnp.Net.Runtime/Rpc/Impatient.cs
@@ -93,6 +93,13 @@ namespace Capnp.Rpc
return answer;
}
+ ///
+ /// Returns a promise-pipelined capability for a remote method invocation Task.
+ ///
+ /// remote method invocation task
+ /// path to the desired capability
+ /// task returning a proxy to the desired capability
+ /// Pipelined low-level capability
public static ConsumedCapability? Access(Task task, MemberAccessPath access, Task proxyTask)
{
var answer = TryGetAnswer(task);
@@ -106,9 +113,6 @@ namespace Capnp.Rpc
///
/// Capability interface type
/// The task
- /// debugging aid
- /// debugging aid
- /// debugging aid
/// A proxy for the given task.
/// is null.
/// did not
diff --git a/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs b/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs
index 3323c16..0889c87 100644
--- a/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs
+++ b/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs
@@ -18,7 +18,7 @@ namespace Capnp.Rpc.Interception
protected override void ReleaseRemotely()
{
- InterceptedCapability.Release(false);
+ InterceptedCapability.Release();
}
internal override IPromisedAnswer DoCall(ulong interfaceId, ushort methodId, DynamicSerializerState args)
diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs
index 696dbbb..08a5437 100644
--- a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs
+++ b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs
@@ -12,7 +12,7 @@ namespace Capnp.Rpc
var result = await answer;
var cap = access.Eval(result);
var proxy = new Proxy(cap);
- cap?.Release(false);
+ cap?.Release();
return proxy;
}
diff --git a/Capnp.Net.Runtime/Rpc/LocalCapability.cs b/Capnp.Net.Runtime/Rpc/LocalCapability.cs
index 5ae7c91..3e1954a 100644
--- a/Capnp.Net.Runtime/Rpc/LocalCapability.cs
+++ b/Capnp.Net.Runtime/Rpc/LocalCapability.cs
@@ -22,7 +22,6 @@ namespace Capnp.Rpc
}
public Skeleton ProvidedCap { get; }
- int _releaseFlag;
LocalCapability(Skeleton providedCap)
{
@@ -31,20 +30,12 @@ namespace Capnp.Rpc
internal override void AddRef()
{
- if (0 == Interlocked.CompareExchange(ref _releaseFlag, 0, 1))
- ProvidedCap.Claim();
+ ProvidedCap.Claim();
}
- internal override void Release(
- bool keepAlive,
- [System.Runtime.CompilerServices.CallerMemberName] string methodName = "",
- [System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
- [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0)
+ internal override void Release()
{
- if (keepAlive)
- Interlocked.Exchange(ref _releaseFlag, 1);
- else
- ProvidedCap.Relinquish();
+ ProvidedCap.Relinquish();
}
internal override IPromisedAnswer DoCall(ulong interfaceId, ushort methodId, DynamicSerializerState args)
diff --git a/Capnp.Net.Runtime/Rpc/PendingAnswer.cs b/Capnp.Net.Runtime/Rpc/PendingAnswer.cs
index 3b4bc38..4bc0f89 100644
--- a/Capnp.Net.Runtime/Rpc/PendingAnswer.cs
+++ b/Capnp.Net.Runtime/Rpc/PendingAnswer.cs
@@ -155,7 +155,7 @@ namespace Capnp.Rpc
{
foreach (var cap in aorcq.Answer.Caps)
{
- cap?.Release(false);
+ cap?.Release();
}
}
}
diff --git a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs
index 548f907..6d4f34c 100644
--- a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs
+++ b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs
@@ -277,13 +277,13 @@ namespace Capnp.Rpc
{
foreach (var cap in inParams.Caps!)
{
- cap?.Release(false);
+ cap?.Release();
}
}
if (target != null)
{
- target.Release(false);
+ target.Release();
}
}
@@ -291,7 +291,7 @@ namespace Capnp.Rpc
{
foreach (var cap in outParams.Caps!)
{
- cap?.Release(false);
+ cap?.Release();
}
}
diff --git a/Capnp.Net.Runtime/Rpc/Proxy.cs b/Capnp.Net.Runtime/Rpc/Proxy.cs
index b6dd739..22957a9 100644
--- a/Capnp.Net.Runtime/Rpc/Proxy.cs
+++ b/Capnp.Net.Runtime/Rpc/Proxy.cs
@@ -11,6 +11,12 @@ namespace Capnp.Rpc
///
public class Proxy : IDisposable, IResolvingCapability
{
+ ///
+ /// Creates a new proxy object for an existing implementation or proxy, sharing its ownership.
+ ///
+ /// Capability interface
+ /// instance to share
+ ///
public static T Share(T obj) where T: class
{
if (obj is Proxy proxy)
@@ -149,14 +155,14 @@ namespace Capnp.Rpc
{
if (disposing)
{
- ConsumedCap?.Release(false);
+ ConsumedCap?.Release();
}
else
{
// When called from the Finalizer, we must not throw.
// But when reference counting goes wrong, ConsumedCapability.Release() will throw an InvalidOperationException.
// The only option here is to suppress that exception.
- try { ConsumedCap?.Release(false); }
+ try { ConsumedCap?.Release(); }
catch { }
}
diff --git a/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs b/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs
index d47a46f..7ad404e 100644
--- a/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs
+++ b/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs
@@ -26,17 +26,8 @@ namespace Capnp.Rpc
// Value 0 has the special meaning of being in state C.
long _refCount = 1;
-#if DebugCapabilityLifecycle || DebugFinalizers
- ILogger Logger { get; } = Logging.CreateLogger();
-#endif
-
-#if DebugCapabilityLifecycle
- string? _releasingMethodName;
- string? _releasingFilePath;
- int _releasingLineNumber;
-#endif
-
#if DebugFinalizers
+ ILogger Logger { get; } = Logging.CreateLogger();
string CreatorStackTrace { get; set; }
#endif
@@ -83,11 +74,7 @@ namespace Capnp.Rpc
{
lock (_reentrancyBlocker)
{
- if (_refCount == int.MinValue)
- {
- _refCount = 2;
- }
- else if (++_refCount <= 1)
+ if (++_refCount <= 1)
{
--_refCount;
@@ -101,30 +88,16 @@ namespace Capnp.Rpc
}
}
- internal sealed override void Release(
- bool keepAlive,
- [System.Runtime.CompilerServices.CallerMemberName] string methodName = "",
- [System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
- [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0)
+ internal sealed override void Release()
{
lock (_reentrancyBlocker)
{
switch (_refCount)
{
- case 2 when keepAlive:
- _refCount = int.MinValue;
- break;
-
case 1: // initial state, actually ref. count 0
case 2: // actually ref. count 1
_refCount = 0;
-#if DebugCapabilityLifecycle
- _releasingMethodName = methodName;
- _releasingFilePath = filePath;
- _releasingLineNumber = lineNumber;
-#endif
-
Dispose(true);
GC.SuppressFinalize(this);
break;
diff --git a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs
index 4631f8b..e2a49ac 100644
--- a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs
+++ b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs
@@ -42,7 +42,7 @@ namespace Capnp.Rpc
var result = await question.WhenReturned;
var cap = access.Eval(result);
var proxy = new Proxy(cap);
- cap?.Release(false);
+ cap?.Release();
return proxy;
}
diff --git a/Capnp.Net.Runtime/Rpc/RpcEngine.cs b/Capnp.Net.Runtime/Rpc/RpcEngine.cs
index 8b6d9ce..195fcd5 100644
--- a/Capnp.Net.Runtime/Rpc/RpcEngine.cs
+++ b/Capnp.Net.Runtime/Rpc/RpcEngine.cs
@@ -60,11 +60,25 @@ namespace Capnp.Rpc
}
}
+ ///
+ /// Stateful implementation for hosting a two-party RPC session. may own multiple mutually
+ /// independent endpoints.
+ ///
public class RpcEndpoint : IEndpoint, IRpcEndpoint
{
+ ///
+ /// Endpoint state
+ ///
public enum EndpointState
{
+ ///
+ /// Active means ready for exchanging RPC messages.
+ ///
Active,
+
+ ///
+ /// The session is closed, either deliberately or due to an error condition.
+ ///
Dismissed
}
@@ -95,8 +109,14 @@ namespace Capnp.Rpc
State = EndpointState.Active;
}
+ ///
+ /// Session state
+ ///
public EndpointState State { get; private set; }
+ ///
+ /// Closes the session, clears export table, terminates all pending questions and enters 'Dismissed' state.
+ ///
public void Dismiss()
{
lock (_reentrancyBlocker)
@@ -120,6 +140,10 @@ namespace Capnp.Rpc
_tx.Dismiss();
}
+ ///
+ /// Feeds a frame for processing
+ ///
+ /// frame to process
public void Forward(WireFrame frame)
{
if (State == EndpointState.Dismissed)
@@ -129,11 +153,43 @@ namespace Capnp.Rpc
ProcessFrame(frame);
}
+ ///
+ /// Number of frames sent so far
+ ///
public long SendCount => Interlocked.Read(ref _sendCount);
+
+ ///
+ /// Number of frames received so far
+ ///
public long RecvCount => Interlocked.Read(ref _recvCount);
- public int ImportedCapabilityCount => _importTable.Count;
- public int ExportedCapabilityCount => _exportTable.Count;
+ ///
+ /// Current number of entries in import table
+ ///
+ public int ImportedCapabilityCount
+ {
+ get
+ {
+ lock (_reentrancyBlocker)
+ {
+ return _importTable.Count;
+ }
+ }
+ }
+
+ ///
+ /// Current number of entries in export table
+ ///
+ public int ExportedCapabilityCount
+ {
+ get
+ {
+ lock (_reentrancyBlocker)
+ {
+ return _exportTable.Count;
+ }
+ }
+ }
void Tx(WireFrame frame)
{
@@ -1095,6 +1151,10 @@ namespace Capnp.Rpc
}
}
+ ///
+ /// Queries the peer for its bootstrap capability
+ ///
+ /// low-level capability
public ConsumedCapability QueryMain()
{
var mb = MessageBuilder.Create();
@@ -1370,7 +1430,7 @@ namespace Capnp.Rpc
else
{
postAction += cap.Export(this, capDesc);
- cap.Release(false);
+ cap.Release();
}
}
@@ -1498,6 +1558,11 @@ namespace Capnp.Rpc
readonly ConcurrentBag _inboundEndpoints = new ConcurrentBag();
+ ///
+ /// Adds an endpoint
+ ///
+ /// endpoint for handling outgoing messages
+ /// endpoint for handling incoming messages
public RpcEndpoint AddEndpoint(IEndpoint outboundEndpoint)
{
var inboundEndpoint = new RpcEndpoint(this, outboundEndpoint);
diff --git a/Capnp.Net.Runtime/SerializerState.cs b/Capnp.Net.Runtime/SerializerState.cs
index 26549f7..8a19bba 100644
--- a/Capnp.Net.Runtime/SerializerState.cs
+++ b/Capnp.Net.Runtime/SerializerState.cs
@@ -1382,15 +1382,19 @@ namespace Capnp
return new Rpc.BareProxy(cap);
}
+ ///
+ /// Releases the capability table
+ ///
public void Dispose()
{
if (Caps != null && !_disposed)
{
foreach (var cap in Caps)
{
- cap?.Release(false);
+ cap?.Release();
}
+ Caps.Clear();
_disposed = true;
}
}