mirror of
https://github.com/FabInfra/capnproto-dotnetcore_Runtime.git
synced 2025-03-12 14:51:41 +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);
|
||||
}
|
||||
|
||||
[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();
|
||||
_fromEnginePump = new FramePump(pipe.Writer.AsStream());
|
||||
_fromEnginePump.AttachTracer(new FrameTracing.RpcFrameTracer(Console.Out, false));
|
||||
_reader = new BinaryReader(pipe.Reader.AsStream());
|
||||
}
|
||||
|
||||
|
@ -276,7 +276,7 @@ namespace Capnp.Net.Runtime.Tests
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ListOfUShorts()
|
||||
public void ListOfUShortsWrongUse()
|
||||
{
|
||||
var b = MessageBuilder.Create();
|
||||
var wrong = b.CreateObject<DynamicSerializerState>();
|
||||
@ -289,6 +289,54 @@ namespace Capnp.Net.Runtime.Tests
|
||||
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]
|
||||
public void ListOfUInts()
|
||||
{
|
||||
@ -1093,7 +1141,7 @@ namespace Capnp.Net.Runtime.Tests
|
||||
{
|
||||
var mb = MessageBuilder.Create();
|
||||
var dss = mb.CreateObject<DynamicSerializerState>();
|
||||
dss.SetStruct(0, 4);
|
||||
dss.SetStruct(0, 5);
|
||||
var s1 = mb.CreateObject<SomeStruct.WRITER>();
|
||||
s1.SomeText = "foo";
|
||||
s1.MoreText = "bar";
|
||||
@ -1109,7 +1157,8 @@ namespace Capnp.Net.Runtime.Tests
|
||||
s4.SomeText = "1";
|
||||
var arr = new SomeStruct.WRITER[] { s3, s4 };
|
||||
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>();
|
||||
Assert.AreEqual("foo", t1.SomeText);
|
||||
@ -1121,7 +1170,8 @@ namespace Capnp.Net.Runtime.Tests
|
||||
Assert.AreEqual(2, l.Count);
|
||||
Assert.AreEqual("0", l[0].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]
|
||||
@ -1138,5 +1188,23 @@ namespace Capnp.Net.Runtime.Tests
|
||||
Assert.IsTrue(cap.IsDisposed);
|
||||
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);
|
||||
|
||||
var client1 = new TcpRpcClient("localhost", TcpPort);
|
||||
Assert.IsTrue(client1.WhenConnected.Wait(MediumNonDbgTimeout));
|
||||
Assert.IsTrue(SpinWait.SpinUntil(() => client1.State == ConnectionState.Down, MediumNonDbgTimeout));
|
||||
Assert.IsTrue(client1.WhenConnected.Wait(MediumNonDbgTimeout), "Did not connect");
|
||||
Assert.IsTrue(SpinWait.SpinUntil(() => client1.State == ConnectionState.Down, MediumNonDbgTimeout),
|
||||
$"Connection did not go down: {client1.State}");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -285,5 +285,17 @@ namespace Capnp.Net.Runtime.Tests
|
||||
{
|
||||
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
|
||||
// the wrapped version.
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
// Also used in some test
|
||||
}
|
||||
catch (System.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:
|
||||
// Since passing a cap has move semantics, we need to create an explicit copy.
|
||||
var copy = Proxy.Share(cap);
|
||||
Assert.IsFalse(((Proxy)copy).IsDisposed);
|
||||
var ctask = main.CallFoo(copy, default);
|
||||
Assert.IsTrue(((Proxy)copy).IsDisposed);
|
||||
testbed.MustComplete(ctask);
|
||||
Assert.AreEqual("bar", ctask.Result);
|
||||
|
||||
@ -820,5 +826,34 @@ namespace Capnp.Net.Runtime.Tests
|
||||
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 MustNotComplete(params Task[] tasks);
|
||||
void FlushCommunication();
|
||||
void CloseClient();
|
||||
void CloseServer();
|
||||
|
||||
long ClientSendCount { get; }
|
||||
}
|
||||
@ -84,7 +86,13 @@ namespace Capnp.Net.Runtime.Tests
|
||||
{
|
||||
var frame = _frameBuffer.Dequeue();
|
||||
_recursion = true;
|
||||
try
|
||||
{
|
||||
OtherEndpoint.Forward(frame);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
}
|
||||
_recursion = false;
|
||||
|
||||
return true;
|
||||
@ -177,6 +185,16 @@ namespace Capnp.Net.Runtime.Tests
|
||||
{
|
||||
Assert.IsFalse(tasks.Any(t => t.IsCompleted));
|
||||
}
|
||||
|
||||
void ITestbed.CloseClient()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
void ITestbed.CloseServer()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
protected class DtbdctTestbed : ITestbed, ITestController
|
||||
@ -231,17 +249,27 @@ namespace Capnp.Net.Runtime.Tests
|
||||
}
|
||||
|
||||
long ITestbed.ClientSendCount => _enginePair.Channel2SendCount;
|
||||
|
||||
void ITestbed.CloseClient()
|
||||
{
|
||||
_enginePair.Endpoint1.Dismiss();
|
||||
}
|
||||
|
||||
void ITestbed.CloseServer()
|
||||
{
|
||||
_enginePair.Endpoint2.Dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
protected class LocalhostTcpTestbed : ITestbed, ITestController
|
||||
{
|
||||
TcpRpcServer _server;
|
||||
TcpRpcClient _client;
|
||||
bool _prematurelyClosed;
|
||||
|
||||
public void RunTest(Action<ITestbed> action)
|
||||
{
|
||||
(_server, _client) = SetupClientServerPair();
|
||||
//_client.WhenConnected.Wait(MediumNonDbgTimeout);
|
||||
Assert.IsTrue(SpinWait.SpinUntil(() => _server.ConnectionCount > 0, MediumNonDbgTimeout));
|
||||
var conn = _server.Connections[0];
|
||||
|
||||
@ -250,10 +278,13 @@ namespace Capnp.Net.Runtime.Tests
|
||||
{
|
||||
action(this);
|
||||
|
||||
if (!_prematurelyClosed)
|
||||
{
|
||||
Assert.IsTrue(SpinWait.SpinUntil(() => _client.SendCount == conn.RecvCount, MediumNonDbgTimeout));
|
||||
Assert.IsTrue(SpinWait.SpinUntil(() => conn.SendCount == _client.RecvCount, MediumNonDbgTimeout));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
T ITestbed.ConnectMain<T>(object main)
|
||||
{
|
||||
@ -293,6 +324,18 @@ namespace Capnp.Net.Runtime.Tests
|
||||
}
|
||||
|
||||
long ITestbed.ClientSendCount => _client.SendCount;
|
||||
|
||||
void ITestbed.CloseClient()
|
||||
{
|
||||
_prematurelyClosed = true;
|
||||
_client.Dispose();
|
||||
}
|
||||
|
||||
void ITestbed.CloseServer()
|
||||
{
|
||||
_prematurelyClosed = true;
|
||||
_server.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public static int TcpPort = 49152;
|
||||
|
@ -31,7 +31,7 @@ namespace Capnp
|
||||
/// <summary>
|
||||
/// The list's data
|
||||
/// </summary>
|
||||
public Span<T> Data => MemoryMarshal.Cast<ulong, T>(RawData);
|
||||
public Span<T> Data => MemoryMarshal.Cast<ulong, T>(RawData).Slice(0, Count);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value at given index.
|
||||
@ -118,7 +118,7 @@ namespace Capnp
|
||||
|
||||
IEnumerable<T> Enumerate()
|
||||
{
|
||||
for (int i = 0; i < Data.Length; i++)
|
||||
for (int i = 0; i < Count; i++)
|
||||
yield return Data[i];
|
||||
}
|
||||
|
||||
|
@ -239,7 +239,7 @@ namespace Capnp.Rpc
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a given type qualifies as cpapbility interface.
|
||||
/// Checks whether a given type qualifies as capability interface.
|
||||
/// </summary>
|
||||
/// <param name="interfaceType">type to check</param>
|
||||
/// <returns>true when <paramref name="interfaceType"/> is a capability interface</returns>
|
||||
|
@ -104,12 +104,6 @@ namespace Capnp.Rpc
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
if (cap == null)
|
||||
{
|
||||
args.Dispose();
|
||||
throw new RpcException("Broken capability");
|
||||
}
|
||||
|
||||
using var proxy = new Proxy(cap);
|
||||
var call = proxy.Call(interfaceId, methodId, args, default);
|
||||
var whenReturned = call.WhenReturned;
|
||||
|
@ -237,28 +237,7 @@ namespace Capnp.Rpc
|
||||
/// <param name="access">Access path</param>
|
||||
/// <returns>Low-level capability</returns>
|
||||
/// <exception cref="DeserializationException">The referenced member does not exist or does not resolve to a capability pointer.</exception>
|
||||
public ConsumedCapability Access(MemberAccessPath 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
public ConsumedCapability Access(MemberAccessPath access) => new RemoteAnswerCapability(this, access);
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
// But when reference counting goes wrong, ConsumedCapability.Release() will throw an InvalidOperationException.
|
||||
// The only option here is to suppress that exception.
|
||||
try { _consumedCap.Release(); }
|
||||
try { _consumedCap?.Release(); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
|
@ -109,18 +109,13 @@ namespace Capnp.Rpc
|
||||
#if DebugEmbargos
|
||||
Logger.LogDebug("Call by proxy");
|
||||
#endif
|
||||
if (_question.StateFlags.HasFlag(PendingQuestion.State.CanceledByDispose))
|
||||
if (_question.StateFlags.HasFlag(PendingQuestion.State.CanceledByDispose) ||
|
||||
_question.StateFlags.HasFlag(PendingQuestion.State.FinishRequested))
|
||||
{
|
||||
args.Dispose();
|
||||
throw new ObjectDisposedException(nameof(PendingQuestion));
|
||||
}
|
||||
|
||||
if (_question.StateFlags.HasFlag(PendingQuestion.State.FinishRequested))
|
||||
{
|
||||
args.Dispose();
|
||||
throw new InvalidOperationException("Finish request was already sent");
|
||||
}
|
||||
|
||||
_question.DisallowFinish();
|
||||
++_pendingCallsOnPromise;
|
||||
var promisedAnswer = base.DoCall(interfaceId, methodId, args);
|
||||
|
@ -437,12 +437,9 @@ namespace Capnp.Rpc
|
||||
why(ret);
|
||||
|
||||
try
|
||||
{
|
||||
lock (_callReturnBlocker)
|
||||
{
|
||||
Tx(mb.Frame);
|
||||
}
|
||||
}
|
||||
catch (RpcException exception)
|
||||
{
|
||||
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;
|
||||
@ -191,8 +192,6 @@ namespace Capnp.Rpc
|
||||
OnConnectionChanged?.Invoke(this, new ConnectionEventArgs(connection));
|
||||
connection.Start();
|
||||
}
|
||||
|
||||
connection.PumpRunner!.Start();
|
||||
}
|
||||
}
|
||||
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>
|
||||
/// Stops accepting incoming attempts and closes all existing connections.
|
||||
/// </summary>
|
||||
@ -260,7 +227,7 @@ namespace Capnp.Rpc
|
||||
{
|
||||
connection.Client.Dispose();
|
||||
connection.Pump?.Dispose();
|
||||
SafeJoin(connection.PumpRunner);
|
||||
connection.PumpRunner?.Join(5000);
|
||||
}
|
||||
|
||||
_rpcEngine.BootstrapCap = null;
|
||||
@ -286,7 +253,8 @@ namespace Capnp.Rpc
|
||||
finally
|
||||
{
|
||||
_listener = null;
|
||||
SafeJoin(_acceptorThread);
|
||||
if (Thread.CurrentThread != _acceptorThread)
|
||||
_acceptorThread?.Join();
|
||||
_acceptorThread = null;
|
||||
}
|
||||
}
|
||||
|
@ -1314,7 +1314,7 @@ namespace Capnp
|
||||
/// </list></param>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="slot"/> is out of range.</exception>
|
||||
/// <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>
|
||||
/// </exception>
|
||||
public void LinkObject<T>(int slot, T obj)
|
||||
@ -1346,10 +1346,16 @@ namespace Capnp
|
||||
break;
|
||||
|
||||
default:
|
||||
if (Rpc.CapabilityReflection.IsValidCapabilityInterface(typeof(T)))
|
||||
try
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ namespace Capnp.Util
|
||||
internal class StrictlyOrderedAwaitTask<T>: INotifyCompletion
|
||||
{
|
||||
readonly Task<T> _awaitedTask;
|
||||
object _lock;
|
||||
object? _lock;
|
||||
long _inOrder, _outOrder;
|
||||
|
||||
public StrictlyOrderedAwaitTask(Task<T> awaitedTask)
|
||||
@ -26,7 +26,7 @@ namespace Capnp.Util
|
||||
|
||||
public async void OnCompleted(Action continuation)
|
||||
{
|
||||
object safeLock = Volatile.Read(ref _lock);
|
||||
object? safeLock = Volatile.Read(ref _lock);
|
||||
|
||||
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();
|
||||
|
||||
|
@ -20,7 +20,7 @@ If(!(test-path $coverageReportDir))
|
||||
}
|
||||
|
||||
& $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.*" `
|
||||
-excludebyattribute:"System.CodeDom.Compiler.GeneratedCodeAttribute" `
|
||||
-output:"$coverageOutput" `
|
||||
|
Loading…
x
Reference in New Issue
Block a user