Updates Pipe & Makes NetState more testable (#288)

Updates pipe eliminate result and segments from being allocated.

Bumps release version
This commit is contained in:
Kamron Batman 2020-10-25 17:40:08 -07:00 committed by GitHub
parent 293e691539
commit 990e6fe188
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 219 additions and 198 deletions

View file

@ -26,7 +26,7 @@ namespace Server.Tests.Network
DelayedExecute(() =>
{
// Write some data into the pipe
var buffer = writer.GetAvailable();
writer.GetAvailable(out var buffer);
Assert.True(buffer.Length == 99);
buffer.CopyFrom(new byte[] { 1 });
@ -37,9 +37,10 @@ namespace Server.Tests.Network
writer.Flush();
});
var result = await reader;
var segments = new ArraySegment<byte>[2];
(await reader).TryRead(segments);
Assert.True(result.Buffer[0].Count == 3);
Assert.True(segments[0].Count == 3);
}
private bool _signal;
@ -53,11 +54,13 @@ namespace Server.Tests.Network
while (count < 0x8000000)
{
var result = reader.TryRead();
reader.TryRead(out var buffer);
for (int i = 0; i < result.Buffer[0].Count; i++)
var first = buffer.GetSpan(0);
for (int i = 0; i < first.Length; i++)
{
Assert.True(result.Buffer[0][i] == expected_value);
Assert.True(first[i] == expected_value);
count++;
if (count == 0x1000)
@ -66,9 +69,10 @@ namespace Server.Tests.Network
}
}
for (int i = 0; i < result.Buffer[1].Count; i++)
var second = buffer.GetSpan(1);
for (int i = 0; i < second.Length; i++)
{
Assert.True(result.Buffer[1][i] == expected_value);
Assert.True(second[i] == expected_value);
count++;
if (count == 0x1000)
@ -77,14 +81,14 @@ namespace Server.Tests.Network
}
}
reader.Advance((uint)result.Length);
reader.Advance((uint)buffer.Length);
}
_signal = true;
}
[Fact]
public async void Threading()
public void Threading()
{
var pipe = new Pipe<byte>(new byte[0x1001]);
@ -97,15 +101,19 @@ namespace Server.Tests.Network
while (count < 0x8000000)
{
var result = writer.GetAvailable();
writer.GetAvailable(out var buffer);
if (result.Length < 16)
if (buffer.Length < 16)
{
continue;
}
result.CopyFrom(new[] { expected_value, expected_value, expected_value, expected_value, expected_value, expected_value, expected_value, expected_value,
expected_value, expected_value, expected_value, expected_value, expected_value, expected_value, expected_value, expected_value });
buffer.CopyFrom(new[] {
expected_value, expected_value, expected_value, expected_value,
expected_value, expected_value, expected_value, expected_value,
expected_value, expected_value, expected_value, expected_value,
expected_value, expected_value, expected_value, expected_value
});
writer.Advance(16);
count += 16;
@ -129,32 +137,33 @@ namespace Server.Tests.Network
var reader = pipe.Reader;
var writer = pipe.Writer;
var result = writer.GetAvailable();
Assert.True(result.Length == 9);
writer.GetAvailable(out var buffer);
Assert.True(buffer.Length == 9);
Assert.True(reader.GetAvailable() == 0);
result = reader.TryRead();
Assert.True(result.Length == 0);
reader.TryRead(out buffer);
Assert.True(buffer.Length == 0);
writer.Advance(7);
result = writer.GetAvailable();
Assert.True(result.Length == 2);
writer.GetAvailable(out buffer);
Assert.True(buffer.Length == 2);
Assert.True(reader.GetAvailable() == 7);
result = reader.TryRead();
Assert.True(result.Length == 7);
reader.TryRead(out buffer);
Assert.True(buffer.Length == 7);
reader.Advance(4);
result = writer.GetAvailable();
Assert.True(result.Length == 6);
writer.GetAvailable(out buffer);
Assert.True(buffer.Length == 6);
Assert.True(reader.GetAvailable() == 3);
result = reader.TryRead();
Assert.True(result.Length == 3);
reader.TryRead(out buffer);
Assert.True(buffer.Length == 3);
writer.Advance(3);
result = writer.GetAvailable();
Assert.True(result.Length == 3);
writer.GetAvailable(out buffer);
Assert.True(buffer.Length == 3);
Assert.True(reader.GetAvailable() == 6);
result = reader.TryRead();
Assert.True(result.Length == 6);
reader.TryRead(out buffer);
Assert.True(buffer.Length == 6);
}
@ -184,7 +193,7 @@ namespace Server.Tests.Network
var reader = pipe.Reader;
var writer = pipe.Writer;
var buffer = writer.GetAvailable();
writer.GetAvailable(out var buffer);
Assert.True(buffer.Length == 9);
buffer.CopyFrom(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 });
@ -194,21 +203,24 @@ namespace Server.Tests.Network
Assert.True(reader.GetAvailable() == 9);
buffer = reader.TryRead();
reader.TryRead(out buffer);
var first = buffer.GetSpan(0);
for (int i = 0; i < 9; i++)
{
Assert.True(buffer.Buffer[0][i] == i);
Assert.True(first[i] == i);
}
reader.Advance(4);
buffer = reader.TryRead();
reader.TryRead(out buffer);
first = buffer.GetSpan(0);
Assert.True(buffer.Length == 5);
Assert.True(buffer.Buffer[0][0] == 4);
Assert.True(buffer.Buffer[0][1] == 5);
Assert.True(buffer.Buffer[0][2] == 6);
Assert.True(buffer.Buffer[0][3] == 7);
Assert.True(buffer.Buffer[0][4] == 8);
Assert.True(first[0] == 4);
Assert.True(first[1] == 5);
Assert.True(first[2] == 6);
Assert.True(first[3] == 7);
Assert.True(first[4] == 8);
}
}
}

View file

@ -15,7 +15,7 @@
namespace System.Buffers
{
public readonly ref struct CircularBuffer<T> where T : struct
public readonly ref struct CircularBuffer<T>
{
private readonly Span<T> _first;
private readonly Span<T> _second;
@ -126,5 +126,15 @@ namespace System.Buffers
return new CircularBuffer<T>(first, second);
}
public Span<T> GetSpan(int index)
{
if (index < 0 || index > 1)
{
throw new ArgumentOutOfRangeException(nameof(index));
}
return index == 0 ? _first : _second;
}
}
}

View file

@ -14,6 +14,7 @@
*************************************************************************/
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.IO;
using System.Runtime.CompilerServices;
@ -30,7 +31,7 @@ namespace Server.Network
public int Position { get; private set; }
public int Remaining => Length - Position;
public CircularBufferReader(ArraySegment<byte>[] buffers) : this(buffers[0], buffers[1])
public CircularBufferReader(ref CircularBuffer<byte> buffer) : this(buffer.GetSpan(0), buffer.GetSpan(1))
{
}

View file

@ -29,10 +29,6 @@ namespace System.Buffers
public int Length { get; }
public int Position { get; private set; }
public CircularBufferWriter(ArraySegment<byte>[] buffers) : this(buffers[0], buffers[1])
{
}
public CircularBufferWriter(Span<byte> first, Span<byte> second)
{
_first = first;

View file

@ -3361,8 +3361,6 @@ namespace Server
m_DeltaQueue.Add(this);
}
}
Core.Set();
}
public void RemDelta(ItemDelta flags)

View file

@ -325,11 +325,6 @@ namespace Server
Console.WriteLine("done");
}
public static void Set()
{
// m_Signal.Set();
}
public static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

View file

@ -8524,8 +8524,6 @@ namespace Server
m_DeltaQueue.Enqueue(this);
}
}
Core.Set();
}
public static void ProcessDeltaQueue()

View file

@ -33,9 +33,9 @@ namespace Server.Network
{
public delegate void NetStateCreatedCallback(NetState ns);
public delegate void EncodePacket(CircularBuffer<byte> buffer, ref int length);
public delegate void EncodePacket(ref CircularBuffer<byte> buffer, ref int length);
public partial class NetState : IComparable<NetState>
public partial class NetState : IComparable<NetState>, IDisposable
{
private static int RecvPipeSize = 1024 * 64;
private static int SendPipeSize = 1024 * 256;
@ -52,9 +52,7 @@ namespace Server.Network
private int m_Disposing;
private ClientVersion m_Version;
private byte[] _recvBuffer;
private Pipe<byte> _recvPipe;
private byte[] _sendBuffer;
private Pipe<byte> _sendPipe;
private long m_NextCheckActivity;
private volatile bool m_Running;
private readonly Thread _sendThread;
@ -89,9 +87,9 @@ namespace Server.Network
Menus = new List<IMenu>();
Trades = new List<SecureTrade>();
_recvBuffer = new byte[RecvPipeSize];
_recvPipe = new Pipe<byte>(_recvBuffer);
RecvPipe = new Pipe<byte>(_recvBuffer);
_sendBuffer = new byte[SendPipeSize];
_sendPipe = new Pipe<byte>(_sendBuffer);
SendPipe = new Pipe<byte>(_sendBuffer);
m_NextCheckActivity = Core.TickCount + 30000;
_sendThread = sendThread ?? Core.Thread;
@ -142,6 +140,10 @@ namespace Server.Network
public bool Seeded { get; set; }
public Pipe<byte> RecvPipe { get; private set; }
public Pipe<byte> SendPipe { get; private set; }
public Socket Connection { get; private set; }
public bool CompressionEnabled { get; set; }
@ -370,29 +372,27 @@ namespace Server.Network
NetworkState.Resume(ref m_NetworkState);
}
public Pipe<byte>.Result<byte> GetAvailableSendPipe() => _recvPipe.Writer.GetAvailable();
public bool GetAvailableSendPipe(out CircularBuffer<byte> buffer) => SendPipe.Writer.GetAvailable(out buffer);
public virtual void Send(CircularBuffer<byte> buffer, int length)
public virtual void Send(ref CircularBuffer<byte> buffer, int length)
{
if (Connection == null || BlockAllPackets || buffer.Length == 0)
{
return;
}
#if DEBUG
var currentThread = Thread.CurrentThread;
if (currentThread != _sendThread)
{
Console.Error.WriteLine("Core: Attempted to send packet outside core thread! [{0}]", currentThread.ManagedThreadId);
#if DEBUG
throw new InvalidThreadException(nameof(Send));
#endif
throw new InvalidThreadException("Attempted to send packet outside send thread!");
}
#endif
try
{
_packetEncoder?.Invoke(buffer, ref length);
_sendPipe.Writer.Advance((uint)length);
_packetEncoder?.Invoke(ref buffer, ref length);
SendPipe.Writer.Advance((uint)length);
}
catch (Exception ex)
{
@ -412,17 +412,16 @@ namespace Server.Network
return;
}
#if DEBUG
var currentThread = Thread.CurrentThread;
if (currentThread != _sendThread)
{
Console.Error.WriteLine("Core: Attempted to send packet outside send thread! [{0}]", currentThread.ManagedThreadId);
#if DEBUG
throw new InvalidThreadException(nameof(Send));
#endif
throw new InvalidThreadException("Attempted to send packet outside send thread!");
}
#endif
var writer = _sendPipe.Writer;
var writer = SendPipe.Writer;
try
{
@ -430,11 +429,15 @@ namespace Server.Network
if (buffer.Length > 0 && length > 0)
{
var result = writer.GetAvailable();
if (result.Length >= length)
if (!GetAvailableSendPipe(out var pipeBuffer))
{
result.CopyFrom(buffer.AsSpan(0, length));
p.OnSend();
return;
}
if (pipeBuffer.Length >= length)
{
pipeBuffer.CopyFrom(buffer.AsSpan(0, length));
writer.Advance((uint)length);
// Flush at the end of the game loop
@ -449,8 +452,6 @@ namespace Server.Network
{
WriteConsole("Didn't write anything!");
}
p.OnSend();
}
catch (Exception ex)
{
@ -460,6 +461,10 @@ namespace Server.Network
#endif
Dispose();
}
finally
{
p.OnSend();
}
}
internal void Start()
@ -477,22 +482,24 @@ namespace Server.Network
private async void SendTask(object state)
{
var reader = _sendPipe.Reader;
var reader = SendPipe.Reader;
var segments = new ArraySegment<byte>[2];
try
{
while (m_Running)
{
var result = await reader.Read();
if (!(await reader).TryRead(segments))
{
break;
}
if (result.Length <= 0)
if (segments[0].Count + segments[1].Count <= 0)
{
continue;
}
var buffer = result.Buffer;
var bytesWritten = await Connection.SendAsync(buffer, SocketFlags.None);
var bytesWritten = await Connection.SendAsync(segments, SocketFlags.None);
if (bytesWritten > 0)
{
@ -517,13 +524,14 @@ namespace Server.Network
private void DecodePacket(ArraySegment<byte>[] buffer, ref int length)
{
CircularBuffer<byte> cBuffer = new CircularBuffer<byte>(buffer);
_packetDecoder?.Invoke(cBuffer, ref length);
_packetDecoder?.Invoke(ref cBuffer, ref length);
}
private async void RecvTask(object state)
{
var socket = Connection;
var writer = _recvPipe.Writer;
var writer = RecvPipe.Writer;
var segments = new ArraySegment<byte>[2];
try
{
@ -534,20 +542,24 @@ namespace Server.Network
continue;
}
var result = writer.GetAvailable();
// TODO: Make awaitable
if (!writer.GetAvailable(segments))
{
break;
}
if (result.Length <= 0)
if (segments[0].Count + segments[1].Count <= 0)
{
continue;
}
var bytesWritten = await socket.ReceiveAsync(result.Buffer, SocketFlags.None);
var bytesWritten = await socket.ReceiveAsync(segments, SocketFlags.None);
if (bytesWritten <= 0)
{
break;
}
DecodePacket(result.Buffer, ref bytesWritten);
DecodePacket(segments, ref bytesWritten);
writer.Advance((uint)bytesWritten);
m_NextCheckActivity = Core.TickCount + 90000;
@ -587,19 +599,17 @@ namespace Server.Network
try
{
var reader = _recvPipe.Reader;
var reader = RecvPipe.Reader;
// Process as many packets as we can synchronously
while (true)
{
var result = reader.TryRead();
if (result.Length <= 0)
if (!reader.TryRead(out var buffer) || buffer.Length <= 0)
{
return;
}
var bytesProcessed = PacketHandlers.ProcessPacket(this, result.Buffer);
var bytesProcessed = PacketHandlers.ProcessPacket(this, ref buffer);
if (bytesProcessed <= 0)
{
@ -630,7 +640,7 @@ namespace Server.Network
{
if (Connection != null)
{
_sendPipe.Writer.Flush();
SendPipe.Writer.Flush();
}
}
@ -715,7 +725,7 @@ namespace Server.Network
return;
}
_sendPipe.Writer.Close();
SendPipe.Writer.Close();
try
{
@ -754,9 +764,9 @@ namespace Server.Network
ns.m_Running = false;
ns.Connection = null;
ns._recvBuffer = null;
ns._recvPipe = null;
ns.RecvPipe = null;
ns._sendBuffer = null;
ns._sendPipe = null;
ns.SendPipe = null;
ns.Gumps.Clear();
ns.Menus.Clear();
ns.HuePickers.Clear();

View file

@ -61,12 +61,12 @@ namespace Server.Network
0x4, 0x00D
};
public static void Compress(CircularBuffer<byte> buffer, ref int length)
public static void Compress(ref CircularBuffer<byte> buffer, ref int length)
{
length = Compress(buffer, length, buffer);
length = Compress(ref buffer, length, ref buffer);
}
public static int Compress(CircularBuffer<byte> input, int inputLength, CircularBuffer<byte> output)
public static int Compress(ref CircularBuffer<byte> input, int inputLength, ref CircularBuffer<byte> output)
{
if (inputLength > DefiniteOverflow)
{

View file

@ -89,8 +89,6 @@ namespace Server.Network
public void OnSend()
{
Core.Set(); // Is this still needed if this is done async?
if ((m_State & (State.Acquired | State.Static)) == 0)
{
Free();

View file

@ -14,6 +14,7 @@
*************************************************************************/
using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO;
using Server.ContextMenus;
@ -46,8 +47,6 @@ namespace Server.Network
public static class PacketHandlers
{
public delegate void PlayCharCallback(NetState state, bool val);
private const int m_AuthIDWindowSize = 128;
private static readonly PacketHandler[] m_6017Handlers = new PacketHandler[0x100];
@ -154,9 +153,6 @@ namespace Server.Network
RegisterEncoded(0x32, true, QuestGumpRequest);
}
public static PlayCharCallback ThirdPartyAuthCallback { get; set; }
public static PlayCharCallback ThirdPartyHackedCallback { get; set; }
public static PacketHandler[] Handlers { get; } = new PacketHandler[0x100];
public static bool SingleClickProps { get; set; }
@ -281,9 +277,9 @@ namespace Server.Network
}
}
public static int ProcessPacket(NetState ns, ArraySegment<byte>[] segments)
public static int ProcessPacket(NetState ns, ref CircularBuffer<byte> buffer)
{
var reader = new CircularBufferReader(segments);
var reader = new CircularBufferReader(ref buffer);
var packetId = reader.ReadByte();

View file

@ -0,0 +1,31 @@
/*************************************************************************
* ModernUO *
* Copyright 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: PacketUtilities.cs *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System.Buffers;
using System.IO;
namespace Server.Network
{
public static class PacketUtilities
{
public static void WritePacketLength(this CircularBufferWriter writer)
{
var length = writer.Position;
writer.Seek(1, SeekOrigin.Begin);
writer.Write((ushort)length);
writer.Seek(length, SeekOrigin.Begin);
}
}
}

View file

@ -14,6 +14,7 @@
*************************************************************************/
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Threading;
@ -32,90 +33,63 @@ namespace Server.Network
public class Pipe<T>
{
public struct Result<T>
{
public ArraySegment<T>[] Buffer { get; }
public bool IsClosed { get; set; }
public int Length
{
get
{
var length = 0;
for (int i = 0; i < Buffer.Length; i++)
{
length += Buffer[i].Count;
}
return length;
}
}
public void CopyFrom(ReadOnlySpan<T> bytes)
{
var remaining = bytes.Length;
var offset = 0;
if (remaining == 0)
{
return;
}
for (int i = 0; i < Buffer.Length; i++)
{
var buffer = Buffer[i];
var sz = Math.Min(remaining, buffer.Count);
bytes.Slice(offset, sz).CopyTo(buffer);
remaining -= sz;
offset += sz;
if (remaining == 0)
{
return;
}
}
throw new OutOfMemoryException();
}
public Result(int segments)
{
IsClosed = false;
Buffer = new ArraySegment<T>[segments];
}
}
public class PipeWriter<T>
{
private readonly Pipe<T> _pipe;
public PipeWriter(Pipe<T> pipe) => _pipe = pipe;
public Result<T> GetAvailable()
public bool GetAvailable(ArraySegment<T>[] segments)
{
var read = _pipe._readIdx;
var write = _pipe._writeIdx;
var result = new Result<T>(2) { IsClosed = _pipe._closed };
if (read <= write)
{
var readZero = read == 0;
var sz = _pipe.Size - write - (readZero ? 1 : 0);
result.Buffer[0] = sz == 0 ? ArraySegment<T>.Empty : new ArraySegment<T>(_pipe._buffer, (int)write, (int)sz);
result.Buffer[1] = readZero ? ArraySegment<T>.Empty : new ArraySegment<T>(_pipe._buffer, 0, (int)read - 1);
segments[0] = sz == 0 ? ArraySegment<T>.Empty : new ArraySegment<T>(_pipe._buffer, (int)write, (int)sz);
segments[1] = readZero ? ArraySegment<T>.Empty : new ArraySegment<T>(_pipe._buffer, 0, (int)read - 1);
}
else
{
var sz = read - write - 1;
result.Buffer[0] = sz == 0 ? ArraySegment<T>.Empty : new ArraySegment<T>(_pipe._buffer, (int)write, (int)sz);
result.Buffer[1] = ArraySegment<T>.Empty;
segments[0] = sz == 0 ? ArraySegment<T>.Empty : new ArraySegment<T>(_pipe._buffer, (int)write, (int)sz);
segments[1] = ArraySegment<T>.Empty;
}
return result;
return !_pipe._closed;
}
public bool GetAvailable(out CircularBuffer<T> buffer)
{
var read = _pipe._readIdx;
var write = _pipe._writeIdx;
Span<T> first;
Span<T> second;
if (read <= write)
{
var readZero = read == 0;
var sz = _pipe.Size - write - (readZero ? 1 : 0);
first = sz == 0 ? Span<T>.Empty : _pipe._buffer.AsSpan((int)write, (int)sz);
second = readZero ? Span<T>.Empty : _pipe._buffer.AsSpan(0, (int)read - 1);
}
else
{
var sz = read - write - 1;
first = sz == 0 ? Span<T>.Empty : _pipe._buffer.AsSpan((int)write, (int)sz);
second = Span<T>.Empty;
}
buffer = new CircularBuffer<T>(first, second);
return !_pipe._closed;
}
public void Advance(uint count)
@ -209,7 +183,7 @@ namespace Server.Network
}
}
public class PipeReader<T> : IPipeTask<Result<T>>
public class PipeReader<T> : IPipeTask<PipeReader<T>>
{
private readonly Pipe<T> _pipe;
@ -229,35 +203,46 @@ namespace Server.Network
return write + _pipe.Size - read;
}
public Result<T> TryRead()
public bool TryRead(out CircularBuffer<T> buffer)
{
var read = _pipe._readIdx;
var write = _pipe._writeIdx;
var result = new Result<T>(2) { IsClosed = _pipe._closed };
Span<T> first;
Span<T> second;
if (read <= write)
{
result.Buffer[0] = write - read == 0 ? ArraySegment<T>.Empty : new ArraySegment<T>(_pipe._buffer, (int)read, (int)(write - read));
result.Buffer[1] = ArraySegment<T>.Empty;
first = write - read == 0 ? Span<T>.Empty : _pipe._buffer.AsSpan((int)read, (int)(write - read));
second = Span<T>.Empty;
}
else
{
result.Buffer[0] = _pipe.Size - read == 0 ? ArraySegment<T>.Empty : new ArraySegment<T>(_pipe._buffer, (int)read, (int)(_pipe.Size - read));
result.Buffer[1] = write == 0 ? ArraySegment<T>.Empty : new ArraySegment<T>(_pipe._buffer, 0, (int)write);
first = _pipe.Size - read == 0 ? Span<T>.Empty : _pipe._buffer.AsSpan((int)read, (int)(_pipe.Size - read));
second = write == 0 ? Span<T>.Empty : _pipe._buffer.AsSpan(0, (int)write);
}
return result;
buffer = new CircularBuffer<T>(first, second);
return !_pipe._closed;
}
public IPipeTask<Result<T>> Read()
public bool TryRead(ArraySegment<T>[] segments)
{
if (_pipe._awaitBeginning)
var read = _pipe._readIdx;
var write = _pipe._writeIdx;
if (read <= write)
{
throw new Exception("Double await on reader");
segments[0] = write - read == 0 ? ArraySegment<T>.Empty : new ArraySegment<T>(_pipe._buffer, (int)read, (int)(write - read));
segments[1] = ArraySegment<T>.Empty;
}
else
{
segments[0] = _pipe.Size - read == 0 ? ArraySegment<T>.Empty : new ArraySegment<T>(_pipe._buffer, (int)read, (int)(_pipe.Size - read));
segments[1] = write == 0 ? ArraySegment<T>.Empty : new ArraySegment<T>(_pipe._buffer, 0, (int)write);
}
return this;
return !_pipe._closed;
}
public void Advance(uint count)
@ -303,7 +288,7 @@ namespace Server.Network
// The following makes it possible to await the reader. Do not use any of this directly.
public IPipeTask<Result<T>> GetAwaiter() => this;
public IPipeTask<PipeReader<T>> GetAwaiter() => this;
public bool IsCompleted
{
@ -319,7 +304,7 @@ namespace Server.Network
}
}
public Result<T> GetResult() => TryRead();
public PipeReader<T> GetResult() => this;
public void OnCompleted(Action continuation) => _pipe._readerContinuation = continuation;

View file

@ -402,8 +402,6 @@ namespace Server
ProcessChanged();
var loaded = false;
for (var i = 0; i < m_Timers.Length; i++)
{
var now = Core.TickCount;
@ -427,8 +425,6 @@ namespace Server
m_Queue.Enqueue(t);
}
loaded = true;
if (t.m_Count != 0 && ++t.m_Index >= t.m_Count)
{
t.Stop();
@ -441,11 +437,6 @@ namespace Server
}
}
if (loaded)
{
Core.Set();
}
m_Signal.WaitOne(1, false);
}
}