mirror of
https://github.com/FabInfra/capnproto-dotnetcore_Runtime.git
synced 2025-03-12 14:51:41 +01:00
tests & fixes
This commit is contained in:
parent
01513ef71f
commit
bdc8240e5b
@ -100,6 +100,8 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsTailCall => false;
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -622,20 +622,6 @@ namespace Capnp.Net.Runtime.Tests.GenImpls
|
|||||||
}
|
}
|
||||||
#endregion TestCallOrder
|
#endregion TestCallOrder
|
||||||
|
|
||||||
#region TestTailCaller
|
|
||||||
class TestTailCaller : ITestTailCaller
|
|
||||||
{
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<TestTailCallee.TailResult> Foo(int i, ITestTailCallee callee, CancellationToken cancellationToken_)
|
|
||||||
{
|
|
||||||
return callee.Foo(i, "from TestTailCaller", cancellationToken_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion TestTailCaller
|
|
||||||
|
|
||||||
#region TestTailCaller
|
#region TestTailCaller
|
||||||
class TestTailCallerImpl : ITestTailCaller
|
class TestTailCallerImpl : ITestTailCaller
|
||||||
{
|
{
|
||||||
@ -660,6 +646,41 @@ namespace Capnp.Net.Runtime.Tests.GenImpls
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TestTailCallerImpl2 : ITestTailCaller
|
||||||
|
{
|
||||||
|
ITestCallOrder _keeper;
|
||||||
|
|
||||||
|
public TestTailCallerImpl2()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_keeper?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<TestTailCallee.TailResult> Foo(int i, ITestTailCallee callee, CancellationToken cancellationToken_)
|
||||||
|
{
|
||||||
|
using (callee)
|
||||||
|
{
|
||||||
|
if (_keeper == null)
|
||||||
|
{
|
||||||
|
var task = callee.Foo(i, "from TestTailCaller", cancellationToken_);
|
||||||
|
_keeper = task.C();
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Task.FromResult(
|
||||||
|
new TestTailCallee.TailResult()
|
||||||
|
{
|
||||||
|
C = _keeper
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
#endregion TestTailCaller
|
#endregion TestTailCaller
|
||||||
|
|
||||||
#region TestTailCallee
|
#region TestTailCallee
|
||||||
@ -937,6 +958,92 @@ namespace Capnp.Net.Runtime.Tests.GenImpls
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TestMoreStuffImpl3 : ITestMoreStuff
|
||||||
|
{
|
||||||
|
readonly TaskCompletionSource<ITestInterface> _heldCap = new TaskCompletionSource<ITestInterface>();
|
||||||
|
|
||||||
|
public Task<string> CallFoo(ITestInterface cap, CancellationToken cancellationToken_ = default)
|
||||||
|
{
|
||||||
|
using (cap)
|
||||||
|
{
|
||||||
|
return cap.Foo(123, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<string> CallFooWhenResolved(ITestInterface Cap, CancellationToken cancellationToken_ = default)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<string> CallHeld(CancellationToken cancellationToken_ = default)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void Dispose()
|
||||||
|
{
|
||||||
|
using (var cap = await _heldCap.Task)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ITestCallOrder> Echo(ITestCallOrder Cap, CancellationToken cancellationToken_ = default)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task ExpectCancel(ITestInterface Cap, CancellationToken cancellationToken_ = default)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<uint> GetCallSequence(uint Expected, CancellationToken cancellationToken_ = default)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<string> GetEnormousString(CancellationToken cancellationToken_ = default)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ITestHandle> GetHandle(CancellationToken cancellationToken_ = default)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ITestInterface> GetHeld(CancellationToken cancellationToken_ = default)
|
||||||
|
{
|
||||||
|
return await _heldCap.Task;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ITestMoreStuff> GetNull(CancellationToken cancellationToken_ = default)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task Hold(ITestInterface Cap, CancellationToken cancellationToken_ = default)
|
||||||
|
{
|
||||||
|
_heldCap.SetResult(Cap);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<(string, string)> MethodWithDefaults(string A, uint B, string C, CancellationToken cancellationToken_ = default)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task MethodWithNullDefault(string A, ITestInterface B, CancellationToken cancellationToken_ = default)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ITestInterface> NeverReturn(ITestInterface Cap, CancellationToken cancellationToken_ = default)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion TestMoreStuff
|
#endregion TestMoreStuff
|
||||||
|
|
||||||
#region TestHandle
|
#region TestHandle
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -173,5 +173,77 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ExportCapToThirdParty()
|
||||||
|
{
|
||||||
|
using (var server = SetupServer())
|
||||||
|
{
|
||||||
|
var counters = new Counters();
|
||||||
|
server.Main = new TestMoreStuffImpl3();
|
||||||
|
|
||||||
|
using (var client = SetupClient())
|
||||||
|
{
|
||||||
|
Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout));
|
||||||
|
|
||||||
|
using (var main = client.GetMain<ITestMoreStuff>())
|
||||||
|
{
|
||||||
|
var held = main.GetHeld().Eager();
|
||||||
|
|
||||||
|
using (var server2 = SetupServer())
|
||||||
|
{
|
||||||
|
server2.Main = new TestMoreStuffImpl2();
|
||||||
|
|
||||||
|
using (var client2 = SetupClient())
|
||||||
|
{
|
||||||
|
Assert.IsTrue(client2.WhenConnected.Wait(MediumNonDbgTimeout));
|
||||||
|
|
||||||
|
using (var main2 = client2.GetMain<ITestMoreStuff>())
|
||||||
|
{
|
||||||
|
var fooTask = main2.CallFoo(held);
|
||||||
|
Assert.IsTrue(main.Hold(new TestInterfaceImpl(new Counters())).Wait(MediumNonDbgTimeout));
|
||||||
|
Assert.IsTrue(fooTask.Wait(MediumNonDbgTimeout));
|
||||||
|
Assert.AreEqual("bar", fooTask.Result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ExportTailCallCapToThirdParty()
|
||||||
|
{
|
||||||
|
using (var server = SetupServer())
|
||||||
|
{
|
||||||
|
server.Main = new TestTailCallerImpl2();
|
||||||
|
|
||||||
|
using (var client = SetupClient())
|
||||||
|
{
|
||||||
|
Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout));
|
||||||
|
|
||||||
|
using (var main = client.GetMain<ITestTailCaller>())
|
||||||
|
{
|
||||||
|
var callee = new TestTailCalleeImpl(new Counters());
|
||||||
|
var fooTask = main.Foo(123, callee);
|
||||||
|
Assert.IsTrue(fooTask.Wait(MediumNonDbgTimeout));
|
||||||
|
|
||||||
|
using (var c = fooTask.Result.C)
|
||||||
|
using (var client2 = SetupClient())
|
||||||
|
{
|
||||||
|
Assert.IsTrue(client2.WhenConnected.Wait(MediumNonDbgTimeout));
|
||||||
|
|
||||||
|
using (var main2 = client2.GetMain<ITestTailCaller>())
|
||||||
|
{
|
||||||
|
var fooTask2 = main2.Foo(123, null);
|
||||||
|
Assert.IsTrue(fooTask2.Wait(MediumNonDbgTimeout));
|
||||||
|
Assert.IsTrue(fooTask2.C().GetCallSequence(1).Wait(MediumNonDbgTimeout));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,9 +193,14 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
|
|
||||||
Assert.AreEqual(0, _enginePair.Endpoint1.ExportedCapabilityCount);
|
Assert.AreEqual(0, _enginePair.Endpoint1.ExportedCapabilityCount);
|
||||||
Assert.AreEqual(0, _enginePair.Endpoint1.ImportedCapabilityCount);
|
Assert.AreEqual(0, _enginePair.Endpoint1.ImportedCapabilityCount);
|
||||||
|
Assert.AreEqual(0, _enginePair.Endpoint1.PendingQuestionCount);
|
||||||
|
Assert.AreEqual(0, _enginePair.Endpoint1.PendingAnswerCount);
|
||||||
|
|
||||||
Assert.AreEqual(0, _enginePair.Endpoint2.ExportedCapabilityCount);
|
Assert.AreEqual(0, _enginePair.Endpoint2.ExportedCapabilityCount);
|
||||||
Assert.AreEqual(0, _enginePair.Endpoint2.ImportedCapabilityCount);
|
Assert.AreEqual(0, _enginePair.Endpoint2.ImportedCapabilityCount);
|
||||||
|
Assert.AreEqual(0, _enginePair.Endpoint2.PendingQuestionCount);
|
||||||
|
Assert.AreEqual(0, _enginePair.Endpoint2.PendingAnswerCount);
|
||||||
|
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
GC.WaitForPendingFinalizers();
|
GC.WaitForPendingFinalizers();
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
|
@ -31,5 +31,10 @@ namespace Capnp.Rpc
|
|||||||
/// <param name="proxyTask">Task returning the proxy whose ownership will be taken over</param>
|
/// <param name="proxyTask">Task returning the proxy whose ownership will be taken over</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
ConsumedCapability? Access(MemberAccessPath access, Task<IDisposable?> proxyTask);
|
ConsumedCapability? Access(MemberAccessPath access, Task<IDisposable?> proxyTask);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the question was asked as tail call
|
||||||
|
/// </summary>
|
||||||
|
bool IsTailCall { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -26,7 +26,11 @@ namespace Capnp.Rpc
|
|||||||
{
|
{
|
||||||
async Task<T> AwaitAnswer()
|
async Task<T> AwaitAnswer()
|
||||||
{
|
{
|
||||||
return then(await promise.WhenReturned);
|
var result = await promise.WhenReturned;
|
||||||
|
if (promise.IsTailCall)
|
||||||
|
throw new TailCallNoDataException();
|
||||||
|
|
||||||
|
return then(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
var rtask = AwaitAnswer();
|
var rtask = AwaitAnswer();
|
||||||
|
@ -70,6 +70,8 @@ namespace Capnp.Rpc.Interception
|
|||||||
_cancelFromAlice.Dispose();
|
_cancelFromAlice.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsTailCall => false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -194,7 +196,7 @@ namespace Capnp.Rpc.Interception
|
|||||||
_censorCapability = censorCapability;
|
_censorCapability = censorCapability;
|
||||||
_promisedAnswer = new PromisedAnswer(this);
|
_promisedAnswer = new PromisedAnswer(this);
|
||||||
_inArgs = inArgs;
|
_inArgs = inArgs;
|
||||||
_bob = null!; // Will beinitialized by setting Bob
|
_bob = null!; // Will be initialized later here
|
||||||
|
|
||||||
CancelFromAlice = _promisedAnswer.CancelFromAlice;
|
CancelFromAlice = _promisedAnswer.CancelFromAlice;
|
||||||
CancelToBob = CancelFromAlice;
|
CancelToBob = CancelFromAlice;
|
||||||
|
@ -25,6 +25,8 @@ namespace Capnp.Rpc
|
|||||||
|
|
||||||
public Task<DeserializerState> WhenReturned { get; }
|
public Task<DeserializerState> WhenReturned { get; }
|
||||||
|
|
||||||
|
public bool IsTailCall => false;
|
||||||
|
|
||||||
public ConsumedCapability Access(MemberAccessPath access)
|
public ConsumedCapability Access(MemberAccessPath access)
|
||||||
{
|
{
|
||||||
return new LocalAnswerCapability(WhenReturned, access);
|
return new LocalAnswerCapability(WhenReturned, access);
|
||||||
|
@ -49,14 +49,14 @@ namespace Capnp.Rpc
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Question object was disposed.
|
/// Question object was disposed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Disposed = 16
|
CanceledByDispose = 16
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly TaskCompletionSource<DeserializerState> _tcs = new TaskCompletionSource<DeserializerState>();
|
readonly TaskCompletionSource<DeserializerState> _tcs = new TaskCompletionSource<DeserializerState>();
|
||||||
readonly uint _questionId;
|
readonly uint _questionId;
|
||||||
ConsumedCapability? _target;
|
ConsumedCapability? _target;
|
||||||
SerializerState? _inParams;
|
SerializerState? _inParams;
|
||||||
int _inhibitFinishCounter;
|
int _inhibitFinishCounter, _refCounter;
|
||||||
|
|
||||||
internal PendingQuestion(IRpcEndpoint ep, uint id, ConsumedCapability? target, SerializerState? inParams)
|
internal PendingQuestion(IRpcEndpoint ep, uint id, ConsumedCapability? target, SerializerState? inParams)
|
||||||
{
|
{
|
||||||
@ -91,10 +91,13 @@ namespace Capnp.Rpc
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Task<DeserializerState> WhenReturned => _tcs.Task;
|
public Task<DeserializerState> WhenReturned => _tcs.Task;
|
||||||
|
|
||||||
internal bool IsTailCall
|
/// <summary>
|
||||||
|
/// Whether this question represents a tail call
|
||||||
|
/// </summary>
|
||||||
|
public bool IsTailCall
|
||||||
{
|
{
|
||||||
get => StateFlags.HasFlag(State.TailCall);
|
get => StateFlags.HasFlag(State.TailCall);
|
||||||
set
|
internal set
|
||||||
{
|
{
|
||||||
if (value)
|
if (value)
|
||||||
StateFlags |= State.TailCall;
|
StateFlags |= State.TailCall;
|
||||||
@ -102,7 +105,6 @@ namespace Capnp.Rpc
|
|||||||
StateFlags &= ~State.TailCall;
|
StateFlags &= ~State.TailCall;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal bool IsReturned => StateFlags.HasFlag(State.Returned);
|
|
||||||
|
|
||||||
internal void DisallowFinish()
|
internal void DisallowFinish()
|
||||||
{
|
{
|
||||||
@ -115,6 +117,23 @@ namespace Capnp.Rpc
|
|||||||
AutoFinish();
|
AutoFinish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void AddRef()
|
||||||
|
{
|
||||||
|
lock (ReentrancyBlocker)
|
||||||
|
{
|
||||||
|
++_refCounter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Release()
|
||||||
|
{
|
||||||
|
lock (ReentrancyBlocker)
|
||||||
|
{
|
||||||
|
--_refCounter;
|
||||||
|
AutoFinish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const string ReturnDespiteTailCallMessage = "Peer sent actual results despite the question was sent as tail call. This was not expected and is a protocol error.";
|
const string ReturnDespiteTailCallMessage = "Peer sent actual results despite the question was sent as tail call. This was not expected and is a protocol error.";
|
||||||
|
|
||||||
internal void OnReturn(DeserializerState results)
|
internal void OnReturn(DeserializerState results)
|
||||||
@ -189,11 +208,6 @@ namespace Capnp.Rpc
|
|||||||
RpcEndpoint.DeleteQuestion(this);
|
RpcEndpoint.DeleteQuestion(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void RequestFinish()
|
|
||||||
{
|
|
||||||
RpcEndpoint.Finish(_questionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoFinish()
|
void AutoFinish()
|
||||||
{
|
{
|
||||||
if (StateFlags.HasFlag(State.FinishRequested))
|
if (StateFlags.HasFlag(State.FinishRequested))
|
||||||
@ -201,12 +215,13 @@ namespace Capnp.Rpc
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((_inhibitFinishCounter == 0 && StateFlags.HasFlag(State.Returned) && !StateFlags.HasFlag(State.TailCall))
|
if ((!IsTailCall && _inhibitFinishCounter == 0 && StateFlags.HasFlag(State.Returned)) ||
|
||||||
|| StateFlags.HasFlag(State.Disposed))
|
( IsTailCall && _refCounter == 0 && StateFlags.HasFlag(State.Returned)) ||
|
||||||
|
StateFlags.HasFlag(State.CanceledByDispose))
|
||||||
{
|
{
|
||||||
StateFlags |= State.FinishRequested;
|
StateFlags |= State.FinishRequested;
|
||||||
|
|
||||||
RequestFinish();
|
RpcEndpoint.Finish(_questionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,9 +353,9 @@ namespace Capnp.Rpc
|
|||||||
|
|
||||||
lock (ReentrancyBlocker)
|
lock (ReentrancyBlocker)
|
||||||
{
|
{
|
||||||
if (!StateFlags.HasFlag(State.Disposed))
|
if (!StateFlags.HasFlag(State.CanceledByDispose))
|
||||||
{
|
{
|
||||||
StateFlags |= State.Disposed;
|
StateFlags |= State.CanceledByDispose;
|
||||||
justDisposed = true;
|
justDisposed = true;
|
||||||
|
|
||||||
AutoFinish();
|
AutoFinish();
|
||||||
|
@ -70,7 +70,7 @@ namespace Capnp.Rpc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed override void AddRef()
|
internal override void AddRef()
|
||||||
{
|
{
|
||||||
lock (_reentrancyBlocker)
|
lock (_reentrancyBlocker)
|
||||||
{
|
{
|
||||||
@ -88,7 +88,7 @@ namespace Capnp.Rpc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed override void Release()
|
internal override void Release()
|
||||||
{
|
{
|
||||||
lock (_reentrancyBlocker)
|
lock (_reentrancyBlocker)
|
||||||
{
|
{
|
||||||
|
@ -122,7 +122,7 @@ namespace Capnp.Rpc
|
|||||||
#if DebugEmbargos
|
#if DebugEmbargos
|
||||||
Logger.LogDebug("Call by proxy");
|
Logger.LogDebug("Call by proxy");
|
||||||
#endif
|
#endif
|
||||||
if (_question.StateFlags.HasFlag(PendingQuestion.State.Disposed))
|
if (_question.StateFlags.HasFlag(PendingQuestion.State.CanceledByDispose))
|
||||||
{
|
{
|
||||||
args.Dispose();
|
args.Dispose();
|
||||||
throw new ObjectDisposedException(nameof(PendingQuestion));
|
throw new ObjectDisposedException(nameof(PendingQuestion));
|
||||||
@ -218,12 +218,12 @@ namespace Capnp.Rpc
|
|||||||
{
|
{
|
||||||
lock (_question.ReentrancyBlocker)
|
lock (_question.ReentrancyBlocker)
|
||||||
{
|
{
|
||||||
if (_question.StateFlags.HasFlag(PendingQuestion.State.Disposed))
|
if (_question.StateFlags.HasFlag(PendingQuestion.State.CanceledByDispose))
|
||||||
throw new ObjectDisposedException(nameof(PendingQuestion));
|
throw new ObjectDisposedException(nameof(PendingQuestion));
|
||||||
|
|
||||||
if (_question.StateFlags.HasFlag(PendingQuestion.State.Returned))
|
if (_question.StateFlags.HasFlag(PendingQuestion.State.Returned) && !_question.IsTailCall)
|
||||||
{
|
{
|
||||||
ResolvedCap?.Export(endpoint, writer);
|
ResolvedCap!.Export(endpoint, writer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -238,10 +238,6 @@ namespace Capnp.Rpc
|
|||||||
}
|
}
|
||||||
else if (_question.IsTailCall)
|
else if (_question.IsTailCall)
|
||||||
{
|
{
|
||||||
// FIXME: Resource management! We should prevent finishing this
|
|
||||||
// cap as long as it is exported. Unfortunately, we cannot determine
|
|
||||||
// when it gets removed from the export table.
|
|
||||||
|
|
||||||
var vine = Vine.Create(this);
|
var vine = Vine.Create(this);
|
||||||
uint id = endpoint.AllocateExport(vine, out bool first);
|
uint id = endpoint.AllocateExport(vine, out bool first);
|
||||||
|
|
||||||
@ -260,8 +256,23 @@ namespace Capnp.Rpc
|
|||||||
|
|
||||||
protected async override void ReleaseRemotely()
|
protected async override void ReleaseRemotely()
|
||||||
{
|
{
|
||||||
try { using var _ = await _whenResolvedProxy; }
|
if (!_question.IsTailCall)
|
||||||
catch { }
|
{
|
||||||
|
try { using var _ = await _whenResolvedProxy; }
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void AddRef()
|
||||||
|
{
|
||||||
|
base.AddRef();
|
||||||
|
_question.AddRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void Release()
|
||||||
|
{
|
||||||
|
_question.Release();
|
||||||
|
base.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -175,6 +175,34 @@ namespace Capnp.Rpc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current number of unanswered questions
|
||||||
|
/// </summary>
|
||||||
|
public int PendingQuestionCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (_reentrancyBlocker)
|
||||||
|
{
|
||||||
|
return _questionTable.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current number of unfinished answers
|
||||||
|
/// </summary>
|
||||||
|
public int PendingAnswerCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (_reentrancyBlocker)
|
||||||
|
{
|
||||||
|
return _answerTable.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Tx(WireFrame frame)
|
void Tx(WireFrame frame)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -281,7 +281,7 @@ namespace Capnp.Rpc
|
|||||||
CheckCtsDisposal();
|
CheckCtsDisposal();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Impl is IDisposable disposable)
|
if (disposing && Impl is IDisposable disposable)
|
||||||
{
|
{
|
||||||
disposable.Dispose();
|
disposable.Dispose();
|
||||||
}
|
}
|
||||||
|
9
Capnp.Net.Runtime/Rpc/TailCallNoDataException.cs
Normal file
9
Capnp.Net.Runtime/Rpc/TailCallNoDataException.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Capnp.Rpc
|
||||||
|
{
|
||||||
|
public class TailCallNoDataException: System.Exception
|
||||||
|
{
|
||||||
|
public TailCallNoDataException(): base("Because the question was asked as tail call, it won't return data")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user