mirror of
https://github.com/FabInfra/capnproto-dotnetcore_Runtime.git
synced 2025-03-12 23:01:44 +01:00
test & fix
This commit is contained in:
parent
a205b45d15
commit
4441ef6c8e
@ -176,5 +176,17 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
{
|
{
|
||||||
NewDtbdctTestbed().RunTest(Testsuite.ReexportSenderPromise);
|
NewDtbdctTestbed().RunTest(Testsuite.ReexportSenderPromise);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CallAfterFinish1()
|
||||||
|
{
|
||||||
|
NewDtbdctTestbed().RunTest(Testsuite.CallAfterFinish1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CallAfterFinish2()
|
||||||
|
{
|
||||||
|
NewDtbdctTestbed().RunTest(Testsuite.CallAfterFinish2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
{
|
{
|
||||||
var pipe = new Pipe();
|
var pipe = new Pipe();
|
||||||
_fromEnginePump = new FramePump(pipe.Writer.AsStream());
|
_fromEnginePump = new FramePump(pipe.Writer.AsStream());
|
||||||
|
_fromEnginePump.AttachTracer(new FrameTracing.RpcFrameTracer(Console.Out, false));
|
||||||
_reader = new BinaryReader(pipe.Reader.AsStream());
|
_reader = new BinaryReader(pipe.Reader.AsStream());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,7 +276,7 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void ListOfUShorts()
|
public void ListOfUShortsWrongUse()
|
||||||
{
|
{
|
||||||
var b = MessageBuilder.Create();
|
var b = MessageBuilder.Create();
|
||||||
var wrong = b.CreateObject<DynamicSerializerState>();
|
var wrong = b.CreateObject<DynamicSerializerState>();
|
||||||
@ -289,6 +289,54 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() => list.ListWriteValue(64, (ushort)1));
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => list.ListWriteValue(64, (ushort)1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ListOfUShortsFromSegment()
|
||||||
|
{
|
||||||
|
var b = MessageBuilder.Create();
|
||||||
|
var list = b.CreateObject<ListOfPrimitivesSerializer<ushort>>();
|
||||||
|
var array = new ushort[] { 1, 2, 3, 4, 5, 6 };
|
||||||
|
var segment = new ArraySegment<ushort>(array, 1, 3);
|
||||||
|
list.Init(segment);
|
||||||
|
CollectionAssert.AreEqual(segment.ToArray(), list.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ListOfUShortsFromDeser()
|
||||||
|
{
|
||||||
|
var b = MessageBuilder.Create();
|
||||||
|
var list0 = b.CreateObject<ListOfPrimitivesSerializer<ushort>>();
|
||||||
|
var expected = new ushort[] { 2, 3, 4 };
|
||||||
|
list0.Init(expected);
|
||||||
|
var deser = ((DeserializerState)list0).RequireList().CastUShort();
|
||||||
|
var list = b.CreateObject<ListOfPrimitivesSerializer<ushort>>();
|
||||||
|
list.Init(deser);
|
||||||
|
CollectionAssert.AreEqual(expected, list.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ListOfUShortsFromSer()
|
||||||
|
{
|
||||||
|
var b = MessageBuilder.Create();
|
||||||
|
var list0 = b.CreateObject<ListOfPrimitivesSerializer<ushort>>();
|
||||||
|
var expected = new ushort[] { 2, 3, 4 };
|
||||||
|
list0.Init(expected);
|
||||||
|
var list = b.CreateObject<ListOfPrimitivesSerializer<ushort>>();
|
||||||
|
list.Init(list0);
|
||||||
|
CollectionAssert.AreEqual(expected, list.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ListOfUShortsFromList()
|
||||||
|
{
|
||||||
|
var b = MessageBuilder.Create();
|
||||||
|
var list0 = b.CreateObject<ListOfPrimitivesSerializer<ushort>>();
|
||||||
|
var expected = new List<ushort> { 2, 3, 4 };
|
||||||
|
list0.Init(expected);
|
||||||
|
var list = b.CreateObject<ListOfPrimitivesSerializer<ushort>>();
|
||||||
|
list.Init(list0);
|
||||||
|
CollectionAssert.AreEqual(expected, list.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void ListOfUInts()
|
public void ListOfUInts()
|
||||||
{
|
{
|
||||||
@ -1093,7 +1141,7 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
{
|
{
|
||||||
var mb = MessageBuilder.Create();
|
var mb = MessageBuilder.Create();
|
||||||
var dss = mb.CreateObject<DynamicSerializerState>();
|
var dss = mb.CreateObject<DynamicSerializerState>();
|
||||||
dss.SetStruct(0, 4);
|
dss.SetStruct(0, 5);
|
||||||
var s1 = mb.CreateObject<SomeStruct.WRITER>();
|
var s1 = mb.CreateObject<SomeStruct.WRITER>();
|
||||||
s1.SomeText = "foo";
|
s1.SomeText = "foo";
|
||||||
s1.MoreText = "bar";
|
s1.MoreText = "bar";
|
||||||
@ -1109,7 +1157,8 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
s4.SomeText = "1";
|
s4.SomeText = "1";
|
||||||
var arr = new SomeStruct.WRITER[] { s3, s4 };
|
var arr = new SomeStruct.WRITER[] { s3, s4 };
|
||||||
dss.LinkObject(2, arr);
|
dss.LinkObject(2, arr);
|
||||||
Assert.ThrowsException<InvalidCapabilityInterfaceException>(() => dss.LinkObject(3, new object()));
|
Assert.ThrowsException<InvalidOperationException>(() => dss.LinkObject(3, new object()));
|
||||||
|
dss.LinkObject(3, new SomeStruct() { SomeText = "corge" });
|
||||||
|
|
||||||
var t1 = dss.BuildPointer(0).Rewrap<SomeStruct.WRITER>();
|
var t1 = dss.BuildPointer(0).Rewrap<SomeStruct.WRITER>();
|
||||||
Assert.AreEqual("foo", t1.SomeText);
|
Assert.AreEqual("foo", t1.SomeText);
|
||||||
@ -1121,7 +1170,8 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
Assert.AreEqual(2, l.Count);
|
Assert.AreEqual(2, l.Count);
|
||||||
Assert.AreEqual("0", l[0].SomeText);
|
Assert.AreEqual("0", l[0].SomeText);
|
||||||
Assert.AreEqual("1", l[1].SomeText);
|
Assert.AreEqual("1", l[1].SomeText);
|
||||||
Assert.AreEqual(ObjectKind.Nil, dss.BuildPointer(3).Kind);
|
Assert.AreEqual("corge", dss.BuildPointer(3).Rewrap<SomeStruct.WRITER>().SomeText);
|
||||||
|
Assert.AreEqual(ObjectKind.Nil, dss.BuildPointer(4).Kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
@ -1138,5 +1188,23 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
Assert.IsTrue(cap.IsDisposed);
|
Assert.IsTrue(cap.IsDisposed);
|
||||||
dss2.Dispose();
|
dss2.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ProvideCapability()
|
||||||
|
{
|
||||||
|
var dss = DynamicSerializerState.CreateForRpc();
|
||||||
|
var impl = new TestInterfaceImpl2();
|
||||||
|
var p1 = (Proxy)Proxy.Share<ITestInterface>(impl);
|
||||||
|
var p2 = (Proxy)Proxy.Share<ITestInterface>(impl);
|
||||||
|
Assert.AreEqual(0u, dss.ProvideCapability(p1));
|
||||||
|
Assert.AreEqual(0u, dss.ProvideCapability(p2.ConsumedCap));
|
||||||
|
Assert.AreEqual(0u, dss.ProvideCapability(CapabilityReflection.CreateSkeleton(impl)));
|
||||||
|
Assert.IsTrue(p1.IsDisposed);
|
||||||
|
Assert.IsFalse(p2.IsDisposed);
|
||||||
|
p2.Dispose();
|
||||||
|
Assert.IsFalse(impl.IsDisposed);
|
||||||
|
dss.Dispose();
|
||||||
|
Assert.IsTrue(impl.IsDisposed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -823,8 +823,9 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
server.StartAccepting(IPAddress.Any, TcpPort);
|
server.StartAccepting(IPAddress.Any, TcpPort);
|
||||||
|
|
||||||
var client1 = new TcpRpcClient("localhost", TcpPort);
|
var client1 = new TcpRpcClient("localhost", TcpPort);
|
||||||
Assert.IsTrue(client1.WhenConnected.Wait(MediumNonDbgTimeout));
|
Assert.IsTrue(client1.WhenConnected.Wait(MediumNonDbgTimeout), "Did not connect");
|
||||||
Assert.IsTrue(SpinWait.SpinUntil(() => client1.State == ConnectionState.Down, MediumNonDbgTimeout));
|
Assert.IsTrue(SpinWait.SpinUntil(() => client1.State == ConnectionState.Down, MediumNonDbgTimeout),
|
||||||
|
$"Connection did not go down: {client1.State}");
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -285,5 +285,17 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
{
|
{
|
||||||
NewLocalhostTcpTestbed().RunTest(Testsuite.NoTailCallMt);
|
NewLocalhostTcpTestbed().RunTest(Testsuite.NoTailCallMt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CallAfterFinish1()
|
||||||
|
{
|
||||||
|
NewLocalhostTcpTestbed().RunTest(Testsuite.CallAfterFinish1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CallAfterFinish2()
|
||||||
|
{
|
||||||
|
NewLocalhostTcpTestbed().RunTest(Testsuite.CallAfterFinish2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,10 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
// exception had to be serialized, so we receive
|
// exception had to be serialized, so we receive
|
||||||
// the wrapped version.
|
// the wrapped version.
|
||||||
}
|
}
|
||||||
|
catch (TaskCanceledException)
|
||||||
|
{
|
||||||
|
// Also used in some test
|
||||||
|
}
|
||||||
catch (System.Exception exception)
|
catch (System.Exception exception)
|
||||||
{
|
{
|
||||||
Assert.Fail($"Got wrong kind of exception: {exception}");
|
Assert.Fail($"Got wrong kind of exception: {exception}");
|
||||||
@ -407,7 +411,9 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
// Note that this was a bug in previous versions:
|
// Note that this was a bug in previous versions:
|
||||||
// Since passing a cap has move semantics, we need to create an explicit copy.
|
// Since passing a cap has move semantics, we need to create an explicit copy.
|
||||||
var copy = Proxy.Share(cap);
|
var copy = Proxy.Share(cap);
|
||||||
|
Assert.IsFalse(((Proxy)copy).IsDisposed);
|
||||||
var ctask = main.CallFoo(copy, default);
|
var ctask = main.CallFoo(copy, default);
|
||||||
|
Assert.IsTrue(((Proxy)copy).IsDisposed);
|
||||||
testbed.MustComplete(ctask);
|
testbed.MustComplete(ctask);
|
||||||
Assert.AreEqual("bar", ctask.Result);
|
Assert.AreEqual("bar", ctask.Result);
|
||||||
|
|
||||||
@ -820,5 +826,34 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
testbed.MustComplete(tcsd.Task);
|
testbed.MustComplete(tcsd.Task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void CallAfterFinish1(ITestbed testbed)
|
||||||
|
{
|
||||||
|
var counters = new Counters();
|
||||||
|
var impl = new TestMoreStuffImpl3();
|
||||||
|
using (var main = testbed.ConnectMain<ITestMoreStuff>(impl))
|
||||||
|
{
|
||||||
|
using (var held = main.GetHeld().Eager())
|
||||||
|
{
|
||||||
|
testbed.CloseClient();
|
||||||
|
testbed.ExpectPromiseThrows(held.Foo(123, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CallAfterFinish2(ITestbed testbed)
|
||||||
|
{
|
||||||
|
var counters = new Counters();
|
||||||
|
var impl = new TestMoreStuffImpl3();
|
||||||
|
using (var main = testbed.ConnectMain<ITestMoreStuff>(impl))
|
||||||
|
{
|
||||||
|
using (var cts = new CancellationTokenSource())
|
||||||
|
using (var held = main.GetHeld(cts.Token).Eager())
|
||||||
|
{
|
||||||
|
cts.Cancel();
|
||||||
|
testbed.ExpectPromiseThrows(held.Foo(123, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
void MustComplete(params Task[] tasks);
|
void MustComplete(params Task[] tasks);
|
||||||
void MustNotComplete(params Task[] tasks);
|
void MustNotComplete(params Task[] tasks);
|
||||||
void FlushCommunication();
|
void FlushCommunication();
|
||||||
|
void CloseClient();
|
||||||
|
void CloseServer();
|
||||||
|
|
||||||
long ClientSendCount { get; }
|
long ClientSendCount { get; }
|
||||||
}
|
}
|
||||||
@ -84,7 +86,13 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
{
|
{
|
||||||
var frame = _frameBuffer.Dequeue();
|
var frame = _frameBuffer.Dequeue();
|
||||||
_recursion = true;
|
_recursion = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
OtherEndpoint.Forward(frame);
|
OtherEndpoint.Forward(frame);
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException)
|
||||||
|
{
|
||||||
|
}
|
||||||
_recursion = false;
|
_recursion = false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -177,6 +185,16 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
{
|
{
|
||||||
Assert.IsFalse(tasks.Any(t => t.IsCompleted));
|
Assert.IsFalse(tasks.Any(t => t.IsCompleted));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ITestbed.CloseClient()
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ITestbed.CloseServer()
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class DtbdctTestbed : ITestbed, ITestController
|
protected class DtbdctTestbed : ITestbed, ITestController
|
||||||
@ -231,17 +249,27 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
long ITestbed.ClientSendCount => _enginePair.Channel2SendCount;
|
long ITestbed.ClientSendCount => _enginePair.Channel2SendCount;
|
||||||
|
|
||||||
|
void ITestbed.CloseClient()
|
||||||
|
{
|
||||||
|
_enginePair.Endpoint1.Dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ITestbed.CloseServer()
|
||||||
|
{
|
||||||
|
_enginePair.Endpoint2.Dismiss();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class LocalhostTcpTestbed : ITestbed, ITestController
|
protected class LocalhostTcpTestbed : ITestbed, ITestController
|
||||||
{
|
{
|
||||||
TcpRpcServer _server;
|
TcpRpcServer _server;
|
||||||
TcpRpcClient _client;
|
TcpRpcClient _client;
|
||||||
|
bool _prematurelyClosed;
|
||||||
|
|
||||||
public void RunTest(Action<ITestbed> action)
|
public void RunTest(Action<ITestbed> action)
|
||||||
{
|
{
|
||||||
(_server, _client) = SetupClientServerPair();
|
(_server, _client) = SetupClientServerPair();
|
||||||
//_client.WhenConnected.Wait(MediumNonDbgTimeout);
|
|
||||||
Assert.IsTrue(SpinWait.SpinUntil(() => _server.ConnectionCount > 0, MediumNonDbgTimeout));
|
Assert.IsTrue(SpinWait.SpinUntil(() => _server.ConnectionCount > 0, MediumNonDbgTimeout));
|
||||||
var conn = _server.Connections[0];
|
var conn = _server.Connections[0];
|
||||||
|
|
||||||
@ -250,10 +278,13 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
{
|
{
|
||||||
action(this);
|
action(this);
|
||||||
|
|
||||||
|
if (!_prematurelyClosed)
|
||||||
|
{
|
||||||
Assert.IsTrue(SpinWait.SpinUntil(() => _client.SendCount == conn.RecvCount, MediumNonDbgTimeout));
|
Assert.IsTrue(SpinWait.SpinUntil(() => _client.SendCount == conn.RecvCount, MediumNonDbgTimeout));
|
||||||
Assert.IsTrue(SpinWait.SpinUntil(() => conn.SendCount == _client.RecvCount, MediumNonDbgTimeout));
|
Assert.IsTrue(SpinWait.SpinUntil(() => conn.SendCount == _client.RecvCount, MediumNonDbgTimeout));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
T ITestbed.ConnectMain<T>(object main)
|
T ITestbed.ConnectMain<T>(object main)
|
||||||
{
|
{
|
||||||
@ -293,6 +324,18 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
long ITestbed.ClientSendCount => _client.SendCount;
|
long ITestbed.ClientSendCount => _client.SendCount;
|
||||||
|
|
||||||
|
void ITestbed.CloseClient()
|
||||||
|
{
|
||||||
|
_prematurelyClosed = true;
|
||||||
|
_client.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ITestbed.CloseServer()
|
||||||
|
{
|
||||||
|
_prematurelyClosed = true;
|
||||||
|
_server.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int TcpPort = 49152;
|
public static int TcpPort = 49152;
|
||||||
|
@ -31,7 +31,7 @@ namespace Capnp
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The list's data
|
/// The list's data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Span<T> Data => MemoryMarshal.Cast<ulong, T>(RawData);
|
public Span<T> Data => MemoryMarshal.Cast<ulong, T>(RawData).Slice(0, Count);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the value at given index.
|
/// Gets or sets the value at given index.
|
||||||
@ -118,7 +118,7 @@ namespace Capnp
|
|||||||
|
|
||||||
IEnumerable<T> Enumerate()
|
IEnumerable<T> Enumerate()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < Data.Length; i++)
|
for (int i = 0; i < Count; i++)
|
||||||
yield return Data[i];
|
yield return Data[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,7 +239,7 @@ namespace Capnp.Rpc
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks whether a given type qualifies as cpapbility interface.
|
/// Checks whether a given type qualifies as capability interface.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="interfaceType">type to check</param>
|
/// <param name="interfaceType">type to check</param>
|
||||||
/// <returns>true when <paramref name="interfaceType"/> is a capability interface</returns>
|
/// <returns>true when <paramref name="interfaceType"/> is a capability interface</returns>
|
||||||
|
@ -104,12 +104,6 @@ namespace Capnp.Rpc
|
|||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cap == null)
|
|
||||||
{
|
|
||||||
args.Dispose();
|
|
||||||
throw new RpcException("Broken capability");
|
|
||||||
}
|
|
||||||
|
|
||||||
using var proxy = new Proxy(cap);
|
using var proxy = new Proxy(cap);
|
||||||
var call = proxy.Call(interfaceId, methodId, args, default);
|
var call = proxy.Call(interfaceId, methodId, args, default);
|
||||||
var whenReturned = call.WhenReturned;
|
var whenReturned = call.WhenReturned;
|
||||||
|
@ -237,28 +237,7 @@ namespace Capnp.Rpc
|
|||||||
/// <param name="access">Access path</param>
|
/// <param name="access">Access path</param>
|
||||||
/// <returns>Low-level capability</returns>
|
/// <returns>Low-level capability</returns>
|
||||||
/// <exception cref="DeserializationException">The referenced member does not exist or does not resolve to a capability pointer.</exception>
|
/// <exception cref="DeserializationException">The referenced member does not exist or does not resolve to a capability pointer.</exception>
|
||||||
public ConsumedCapability Access(MemberAccessPath access)
|
public ConsumedCapability Access(MemberAccessPath access) => new RemoteAnswerCapability(this, access);
|
||||||
{
|
|
||||||
lock (ReentrancyBlocker)
|
|
||||||
{
|
|
||||||
if ( StateFlags.HasFlag(State.Returned) &&
|
|
||||||
!StateFlags.HasFlag(State.TailCall))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return access.Eval(WhenReturned.Result);
|
|
||||||
}
|
|
||||||
catch (AggregateException exception)
|
|
||||||
{
|
|
||||||
throw exception.InnerException!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new RemoteAnswerCapability(this, access);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Refer to a (possibly nested) member of this question's (possibly future) result and return
|
/// Refer to a (possibly nested) member of this question's (possibly future) result and return
|
||||||
|
@ -161,7 +161,7 @@ namespace Capnp.Rpc
|
|||||||
// When called from the Finalizer, we must not throw.
|
// When called from the Finalizer, we must not throw.
|
||||||
// But when reference counting goes wrong, ConsumedCapability.Release() will throw an InvalidOperationException.
|
// But when reference counting goes wrong, ConsumedCapability.Release() will throw an InvalidOperationException.
|
||||||
// The only option here is to suppress that exception.
|
// The only option here is to suppress that exception.
|
||||||
try { _consumedCap.Release(); }
|
try { _consumedCap?.Release(); }
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,18 +109,13 @@ 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.CanceledByDispose))
|
if (_question.StateFlags.HasFlag(PendingQuestion.State.CanceledByDispose) ||
|
||||||
|
_question.StateFlags.HasFlag(PendingQuestion.State.FinishRequested))
|
||||||
{
|
{
|
||||||
args.Dispose();
|
args.Dispose();
|
||||||
throw new ObjectDisposedException(nameof(PendingQuestion));
|
throw new ObjectDisposedException(nameof(PendingQuestion));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_question.StateFlags.HasFlag(PendingQuestion.State.FinishRequested))
|
|
||||||
{
|
|
||||||
args.Dispose();
|
|
||||||
throw new InvalidOperationException("Finish request was already sent");
|
|
||||||
}
|
|
||||||
|
|
||||||
_question.DisallowFinish();
|
_question.DisallowFinish();
|
||||||
++_pendingCallsOnPromise;
|
++_pendingCallsOnPromise;
|
||||||
var promisedAnswer = base.DoCall(interfaceId, methodId, args);
|
var promisedAnswer = base.DoCall(interfaceId, methodId, args);
|
||||||
|
@ -437,12 +437,9 @@ namespace Capnp.Rpc
|
|||||||
why(ret);
|
why(ret);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
|
||||||
lock (_callReturnBlocker)
|
|
||||||
{
|
{
|
||||||
Tx(mb.Frame);
|
Tx(mb.Frame);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (RpcException exception)
|
catch (RpcException exception)
|
||||||
{
|
{
|
||||||
Logger.LogWarning($"Unable to return call: {exception.InnerException?.Message ?? exception.Message}");
|
Logger.LogWarning($"Unable to return call: {exception.InnerException?.Message ?? exception.Message}");
|
||||||
|
@ -110,6 +110,7 @@ namespace Capnp.Rpc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
PumpRunner.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConnectionState State { get; set; } = ConnectionState.Initializing;
|
public ConnectionState State { get; set; } = ConnectionState.Initializing;
|
||||||
@ -191,8 +192,6 @@ namespace Capnp.Rpc
|
|||||||
OnConnectionChanged?.Invoke(this, new ConnectionEventArgs(connection));
|
OnConnectionChanged?.Invoke(this, new ConnectionEventArgs(connection));
|
||||||
connection.Start();
|
connection.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
connection.PumpRunner!.Start();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (SocketException)
|
catch (SocketException)
|
||||||
@ -207,38 +206,6 @@ namespace Capnp.Rpc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SafeJoin(Thread? thread)
|
|
||||||
{
|
|
||||||
if (thread == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int retry = 0; retry < 5; ++retry)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!thread.Join(500))
|
|
||||||
{
|
|
||||||
Logger.LogError($"Unable to join {thread.Name} within timeout");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
catch (ThreadStateException)
|
|
||||||
{
|
|
||||||
// In rare cases it happens that despite thread.Start() was called, the thread did not actually start yet.
|
|
||||||
Logger.LogDebug("Waiting for thread to start in order to join it");
|
|
||||||
Thread.Sleep(100);
|
|
||||||
}
|
|
||||||
catch (System.Exception exception)
|
|
||||||
{
|
|
||||||
Logger.LogError($"Unable to join {thread.Name}: {exception.Message}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stops accepting incoming attempts and closes all existing connections.
|
/// Stops accepting incoming attempts and closes all existing connections.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -260,7 +227,7 @@ namespace Capnp.Rpc
|
|||||||
{
|
{
|
||||||
connection.Client.Dispose();
|
connection.Client.Dispose();
|
||||||
connection.Pump?.Dispose();
|
connection.Pump?.Dispose();
|
||||||
SafeJoin(connection.PumpRunner);
|
connection.PumpRunner?.Join(5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
_rpcEngine.BootstrapCap = null;
|
_rpcEngine.BootstrapCap = null;
|
||||||
@ -286,7 +253,8 @@ namespace Capnp.Rpc
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_listener = null;
|
_listener = null;
|
||||||
SafeJoin(_acceptorThread);
|
if (Thread.CurrentThread != _acceptorThread)
|
||||||
|
_acceptorThread?.Join();
|
||||||
_acceptorThread = null;
|
_acceptorThread = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1314,7 +1314,7 @@ namespace Capnp
|
|||||||
/// </list></param>
|
/// </list></param>
|
||||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="slot"/> is out of range.</exception>
|
/// <exception cref="ArgumentOutOfRangeException"><paramref name="slot"/> is out of range.</exception>
|
||||||
/// <exception cref="InvalidOperationException"><list type="bullet">
|
/// <exception cref="InvalidOperationException"><list type="bullet">
|
||||||
/// <item><description>This state does neither describe a struct, nor a list of pointers</description></item>
|
/// <item><description>Object neither describes a struct, nor a list of pointers, nor a capability</description></item>
|
||||||
/// <item><description>Another state is already linked to the specified position (sorry, no overwrite allowed)</description></item></list>
|
/// <item><description>Another state is already linked to the specified position (sorry, no overwrite allowed)</description></item></list>
|
||||||
/// </exception>
|
/// </exception>
|
||||||
public void LinkObject<T>(int slot, T obj)
|
public void LinkObject<T>(int slot, T obj)
|
||||||
@ -1346,10 +1346,16 @@ namespace Capnp
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (Rpc.CapabilityReflection.IsValidCapabilityInterface(typeof(T)))
|
try
|
||||||
{
|
{
|
||||||
LinkToCapability(slot, ProvideCapability(obj));
|
LinkToCapability(slot, ProvideCapability(obj));
|
||||||
}
|
}
|
||||||
|
catch (Exception exception) when (
|
||||||
|
exception is Rpc.InvalidCapabilityInterfaceException ||
|
||||||
|
exception is InvalidOperationException)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Object neither describes a struct, nor a list of pointers, nor a capability", exception);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ namespace Capnp.Util
|
|||||||
internal class StrictlyOrderedAwaitTask<T>: INotifyCompletion
|
internal class StrictlyOrderedAwaitTask<T>: INotifyCompletion
|
||||||
{
|
{
|
||||||
readonly Task<T> _awaitedTask;
|
readonly Task<T> _awaitedTask;
|
||||||
object _lock;
|
object? _lock;
|
||||||
long _inOrder, _outOrder;
|
long _inOrder, _outOrder;
|
||||||
|
|
||||||
public StrictlyOrderedAwaitTask(Task<T> awaitedTask)
|
public StrictlyOrderedAwaitTask(Task<T> awaitedTask)
|
||||||
@ -26,7 +26,7 @@ namespace Capnp.Util
|
|||||||
|
|
||||||
public async void OnCompleted(Action continuation)
|
public async void OnCompleted(Action continuation)
|
||||||
{
|
{
|
||||||
object safeLock = Volatile.Read(ref _lock);
|
object? safeLock = Volatile.Read(ref _lock);
|
||||||
|
|
||||||
if (safeLock == null)
|
if (safeLock == null)
|
||||||
{
|
{
|
||||||
@ -69,7 +69,7 @@ namespace Capnp.Util
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsCompleted => Volatile.Read(ref _lock) == null;
|
public bool IsCompleted => Volatile.Read(ref _lock) == null || (_awaitedTask.IsCompleted && Volatile.Read(ref _inOrder) == 0);
|
||||||
|
|
||||||
public T GetResult() => _awaitedTask.GetAwaiter().GetResult();
|
public T GetResult() => _awaitedTask.GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ If(!(test-path $coverageReportDir))
|
|||||||
}
|
}
|
||||||
|
|
||||||
& $openCover -target:"$vsTestConsole" `
|
& $openCover -target:"$vsTestConsole" `
|
||||||
-targetArgs:"/inIsolation $runtimeTests /TestCaseFilter:`"TestCategory=Coverage`"" `
|
-targetArgs:"/inIsolation $runtimeTests /TestCaseFilter:`"TestCategory=Coverage`" /Framework:.NETCoreApp,Version=v2.1" `
|
||||||
-filter:"+[Capnp.Net.Runtime]Capnp.*" `
|
-filter:"+[Capnp.Net.Runtime]Capnp.*" `
|
||||||
-excludebyattribute:"System.CodeDom.Compiler.GeneratedCodeAttribute" `
|
-excludebyattribute:"System.CodeDom.Compiler.GeneratedCodeAttribute" `
|
||||||
-output:"$coverageOutput" `
|
-output:"$coverageOutput" `
|
||||||
|
Loading…
x
Reference in New Issue
Block a user