Пример #1
0
        public override async ReusableTask WriteAsync(ITorrentFileInfo file, long offset, byte[] buffer, int bufferOffset, int count)
        {
            var tcs = new ReusableTaskCompletionSource <object> ();

            Writes.Add(tcs);
            await tcs.Task;
        }
Пример #2
0
        public static async ReusableTask ReceiveAsync(IConnection connection, ByteBuffer buffer, int offset, int count, IRateLimiter rateLimiter, SpeedMonitor peerMonitor, SpeedMonitor managerMonitor)
        {
            await MainLoop.SwitchToThreadpool();

            while (count > 0)
            {
                int  transferred;
                bool unlimited  = rateLimiter?.Unlimited ?? true;
                int  shouldRead = unlimited ? count : Math.Min(ChunkLength, count);

                if (rateLimiter != null && !unlimited && !rateLimiter.TryProcess(shouldRead))
                {
                    var tcs = new ReusableTaskCompletionSource <int> ();
                    lock (receiveQueue)
                        receiveQueue.Enqueue(new QueuedIO(connection, buffer, offset, shouldRead, rateLimiter, tcs));
                    transferred = await tcs.Task.ConfigureAwait(false);
                }
                else
                {
                    transferred = await connection.ReceiveAsync(buffer, offset, shouldRead).ConfigureAwait(false);
                }

                if (transferred == 0)
                {
                    throw new ConnectionClosedException("Socket receive returned 0, indicating the connection has been closed.");
                }

                peerMonitor?.AddDelta(transferred);
                managerMonitor?.AddDelta(transferred);

                offset += transferred;
                count  -= transferred;
            }
        }
Пример #3
0
        public static async ReusableTask SendAsync(IConnection2 connection, byte [] buffer, int offset, int count, IRateLimiter rateLimiter, SpeedMonitor peerMonitor, SpeedMonitor managerMonitor)
        {
            await IOLoop;

            while (count > 0)
            {
                int  transferred;
                bool unlimited  = rateLimiter?.Unlimited ?? true;
                var  shouldRead = unlimited ? count : Math.Min(ChunkLength, count);

                if (rateLimiter != null && !unlimited && !rateLimiter.TryProcess(shouldRead))
                {
                    var   tcs = new ReusableTaskCompletionSource <int> ();
                    await IOLoop;
                    sendQueue.Enqueue(new QueuedIO(connection, buffer, offset, shouldRead, rateLimiter, tcs));
                    transferred = await tcs.Task.ConfigureAwait(false);
                }
                else
                {
                    transferred = await connection.SendAsync(buffer, offset, shouldRead).ConfigureAwait(false);
                }

                if (transferred == 0)
                {
                    throw new Exception("Socket is dead");
                }

                peerMonitor?.AddDelta(transferred);
                managerMonitor?.AddDelta(transferred);

                offset += transferred;
                count  -= transferred;
            }
        }
        public override async ReusableTask WriteAsync(ITorrentManagerFile file, long offset, ReadOnlyMemory <byte> buffer)
        {
            var tcs = new ReusableTaskCompletionSource <object> ();

            Writes.Add(tcs);
            await tcs.Task;
        }
Пример #5
0
 public QueuedIO(IPeerConnection connection, SocketMemory buffer, IRateLimiter rateLimiter, ReusableTaskCompletionSource <int> tcs)
 {
     this.connection  = connection;
     this.buffer      = buffer;
     this.rateLimiter = rateLimiter;
     this.tcs         = tcs;
 }
    public async Task AllCombinations()
    {
        var tcs = new ReusableTaskCompletionSource <int>();

        // write then read

        tcs.SetResult(1, true);
        var r1 = await tcs.GetResultAsync().ConfigureAwait(false);

        Assert.Equal(1, r1);

        // read then write

        var r2 = tcs.GetResultAsync();

        Assert.False(r2.IsCompleted);

        tcs.SetResult(2, true);
        Assert.Equal(2, await r2.ConfigureAwait(false));

        // read and await then write

        var r3 = Await(tcs.GetResultAsync());

        Assert.False(r3.IsCompleted);

        tcs.SetResult(3, true);
        Assert.Equal(3, await r3.ConfigureAwait(false));
    }
Пример #7
0
        public async ReusableTask <Socket> ConnectAsync(Uri uri, CancellationToken token)
        {
            var socket   = new Socket((uri.Scheme == "ipv4") ? AddressFamily.InterNetwork : AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
            var endPoint = new IPEndPoint(IPAddress.Parse(uri.Host), uri.Port);

            using var registration = token.Register(SocketDisposer, socket);
            var tcs = new ReusableTaskCompletionSource <int> ();
            SocketAsyncEventArgs args = GetSocketAsyncEventArgs();

            args.RemoteEndPoint = endPoint;
            args.UserToken      = tcs;

            try {
                if (!socket.ConnectAsync(args))
                {
                    tcs.SetResult(0);
                }

                await tcs.Task;
            } catch {
                socket.Dispose();
                throw;
            } finally {
                args.RemoteEndPoint = null;
                args.UserToken      = null;
                lock (cache)
                    cache.Enqueue(args);
            }
            return(socket);
        }
Пример #8
0
    public async Task PingPong()
    {
        const int iterations = 1_000_000;

        var left  = new ReusableTaskCompletionSource <int>();
        var right = new ReusableTaskCompletionSource <int>();

        async Task TestLeft()
        {
            for (int x = 0; x < iterations; ++x)
            {
                left.SetResult(x, true);
                (await right.GetResultAsync().ConfigureAwait(false)).Expect(x);
            }
        }

        async Task TestRight()
        {
            for (int x = 0; x < iterations; ++x)
            {
                (await left.GetResultAsync().ConfigureAwait(false)).Expect(x);
                right.SetResult(x, true);
            }
        }

        var t1 = TestLeft();
        var t2 = TestRight();

        await t1;
        await t2;
    }
Пример #9
0
        async ReusableTask WaitForPendingWrites()
        {
            var tcs = new ReusableTaskCompletionSource <bool>();

            WriteQueue.Enqueue(new BufferedIO(null, -1, null, -1, tcs));
            await tcs.Task;
        }
Пример #10
0
        public async Task ExceedMaxOpenFiles()
        {
            var streams       = new List <ManualStream> ();
            var streamCreated = new ReusableTaskCompletionSource <bool> ();
            Func <ITorrentFileInfo, FileAccess, ITorrentFileStream> creator = (file, access) => {
                var s = new ManualStream(file, access);
                s.WriteTcs = new ReusableTaskCompletionSource <int> ();
                streams.Add(s);
                streamCreated.SetResult(true);
                return(s);
            };

            using var writer = new DiskWriter(creator, 1);

            var writeTask = writer.WriteAsync(TorrentFile, 0, new byte[100], 0, 100);
            await streamCreated.Task.WithTimeout();

            // There's a limit of 1 concurrent read/write.
            var secondStreamWaiter = streamCreated.Task.AsTask();
            var secondStream       = writer.WriteAsync(Others.First(), 0, new byte[100], 0, 100);

            Assert.ThrowsAsync <TimeoutException> (() => secondStreamWaiter.WithTimeout(100));

            streams[0].WriteTcs.SetResult(1);
            await secondStreamWaiter.WithTimeout();

            streams[1].WriteTcs.SetResult(1);

            await secondStream.WithTimeout();

            Assert.IsTrue(streams[0].Disposed);
            Assert.IsFalse(streams[1].Disposed);
        }
Пример #11
0
        public static async ReusableTask SendAsync(IPeerConnection connection, SocketMemory buffer, IRateLimiter rateLimiter, SpeedMonitor peerMonitor, SpeedMonitor managerMonitor)
        {
            await MainLoop.SwitchToThreadpool();

            while (buffer.Length > 0)
            {
                int  transferred;
                bool unlimited  = rateLimiter?.Unlimited ?? true;
                int  shouldRead = unlimited ? buffer.Length : Math.Min(ChunkLength, buffer.Length);

                if (rateLimiter != null && !unlimited && !rateLimiter.TryProcess(shouldRead))
                {
                    var tcs = new ReusableTaskCompletionSource <int> ();
                    lock (sendQueue)
                        sendQueue.Enqueue(new QueuedIO(connection, buffer.Slice(0, shouldRead), rateLimiter, tcs));
                    transferred = await tcs.Task.ConfigureAwait(false);
                }
                else
                {
                    transferred = await connection.SendAsync(buffer.Slice(0, shouldRead)).ConfigureAwait(false);
                }

                if (transferred == 0)
                {
                    throw new ConnectionClosedException("Socket send returned 0, indicating the connection has been closed.");
                }

                peerMonitor?.AddDelta(transferred);
                managerMonitor?.AddDelta(transferred);

                buffer = buffer.Slice(transferred);
            }
        }
Пример #12
0
 SocketConnection(Socket socket, IPEndPoint endpoint, bool isIncoming)
 {
     ReceiveTcs = new ReusableTaskCompletionSource <int> ();
     SendTcs    = new ReusableTaskCompletionSource <int> ();
     Socket     = socket;
     EndPoint   = endpoint;
     IsIncoming = isIncoming;
 }
Пример #13
0
 public BufferedIO(ITorrentData manager, long offset, byte[] buffer, int count, ReusableTaskCompletionSource <bool> tcs)
 {
     this.manager = manager;
     this.offset  = offset;
     this.buffer  = buffer;
     this.count   = count;
     this.tcs     = tcs;
 }
 public BufferedIO(ITorrentManagerInfo?manager, BlockInfo request, Memory <byte> buffer, bool preferSkipCache, ReusableTaskCompletionSource <bool> tcs)
 {
     this.manager         = manager;
     this.request         = request;
     this.buffer          = buffer;
     this.preferSkipCache = preferSkipCache;
     this.tcs             = tcs;
 }
Пример #15
0
 public QueuedIO(IConnection2 connection, byte [] buffer, int offset, int count, IRateLimiter rateLimiter, ReusableTaskCompletionSource <int> tcs)
 {
     this.connection  = connection;
     this.buffer      = buffer;
     this.offset      = offset;
     this.count       = count;
     this.rateLimiter = rateLimiter;
     this.tcs         = tcs;
 }
        public async Task UseTwice()
        {
            var tcs = new ReusableTaskCompletionSource <int> ();

            tcs.SetResult(1);
            Assert.IsTrue(tcs.Task.IsCompleted, "#1");
            Assert.AreEqual(1, await tcs.Task, "#2");
            Assert.IsFalse(tcs.Task.IsCompleted, "#3");
            Assert.AreEqual(0, ReusableTaskMethodBuilder <int> .CacheCount, "#4");

            tcs.SetResult(2);
            Assert.AreEqual(2, await tcs.Task, "#6");
            Assert.AreEqual(0, ReusableTaskMethodBuilder <int> .CacheCount, "#7");
        }
Пример #17
0
        internal async ReusableTask WriteAsync(ITorrentData manager, long offset, byte[] buffer, int count)
        {
            if (count < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(count), $"Count must be greater than zero, but was {count}.");
            }

            Interlocked.Add(ref pendingWrites, count);
            await IOLoop;

            int  pieceIndex = (int)(offset / manager.PieceLength);
            long pieceStart = (long)pieceIndex * manager.PieceLength;
            long pieceEnd   = pieceStart + manager.PieceLength;

            if (!IncrementalHashes.TryGetValue(ValueTuple.Create(manager, pieceIndex), out IncrementalHashData incrementalHash) && offset == pieceStart)
            {
                incrementalHash = IncrementalHashes[ValueTuple.Create(manager, pieceIndex)] = IncrementalHashCache.Dequeue();
                incrementalHash.NextOffsetToHash = (long)manager.PieceLength * pieceIndex;
            }

            if (incrementalHash != null)
            {
                // Incremental hashing does not perform proper bounds checking to ensure
                // that pieces are correctly incrementally hashed even if 'count' is greater
                // than the PieceLength. This should never happen under normal operation, but
                // unit tests do it for convenience sometimes. Keep things safe by cancelling
                // incremental hashing if that occurs.
                if ((incrementalHash.NextOffsetToHash + count) > pieceEnd)
                {
                    IncrementalHashes.Remove(ValueTuple.Create(manager, pieceIndex));
                }
                else if (incrementalHash.NextOffsetToHash == offset)
                {
                    incrementalHash.Hasher.TransformBlock(buffer, 0, count, buffer, 0);
                    incrementalHash.NextOffsetToHash += count;
                }
            }

            if (WriteLimiter.TryProcess(count))
            {
                Interlocked.Add(ref pendingWrites, -count);
                Write(manager, offset, buffer, count);
            }
            else
            {
                var tcs = new ReusableTaskCompletionSource <bool> ();
                WriteQueue.Enqueue(new BufferedIO(manager, offset, buffer, count, tcs));
                await tcs.Task;
            }
        }
Пример #18
0
        public async ReusableTask ConnectAsync()
        {
            var tcs = new ReusableTaskCompletionSource <int> ();
            SocketAsyncEventArgs args = GetSocketAsyncEventArgs(null);

            args.RemoteEndPoint = EndPoint;
            args.UserToken      = tcs;

            if (!Socket.ConnectAsync(args))
            {
                tcs.SetResult(0);
            }

            await tcs.Task;
        }
        public async Task DoNotForceAsyncWithSyncContext()
        {
            await TestSynchronizationContext.Instance;

            TestSynchronizationContext.Instance.ResetCounts();

            var tcs = new ReusableTaskCompletionSource <int> (false);

            tcs.SetResult(1);

            // If we are not forcing async, we do allow synchronous completion.
            Assert.IsTrue(tcs.Task.IsCompleted, "#1");
            await tcs.Task;

            Assert.AreEqual(0, TestSynchronizationContext.Instance.Posted, "#2");
        }
        public async Task ForceAsyncWithSyncContext()
        {
            await TestSynchronizationContext.Instance;

            TestSynchronizationContext.Instance.ResetCounts();

            var tcs = new ReusableTaskCompletionSource <int> (true);

            tcs.SetResult(1);

            // If we're forcing async, we have to explicitly disallow synchronous completion too.
            Assert.IsFalse(tcs.Task.IsCompleted, "#1");
            await tcs.Task;

            Assert.AreEqual(1, TestSynchronizationContext.Instance.Posted, "#2");
        }
Пример #21
0
        internal async ReusableTask <bool> ReadAsync(ITorrentData manager, long offset, byte [] buffer, int count)
        {
            Interlocked.Add(ref pendingReads, count);
            await IOLoop;

            if (ReadLimiter.TryProcess(count))
            {
                Interlocked.Add(ref pendingReads, -count);
                return(Read(manager, offset, buffer, count));
            }
            else
            {
                var tcs = new ReusableTaskCompletionSource <bool>();
                ReadQueue.Enqueue(new BufferedIO(manager, offset, buffer, count, tcs));
                return(await tcs.Task);
            }
        }
        SocketPeerConnection(Uri?uri, ISocketConnector?connector, Socket?socket, bool isIncoming)
        {
            if (uri == null)
            {
                var endpoint = (IPEndPoint)socket !.RemoteEndPoint !;
                uri = new Uri($"{(socket.AddressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6") }://{endpoint.Address}{':'}{endpoint.Port}");
            }

            ConnectCancellation = new CancellationTokenSource();
            Connector           = connector;
            EndPoint            = new IPEndPoint(IPAddress.Parse(uri.Host), uri.Port);
            IsIncoming          = isIncoming;
            Socket = socket;
            Uri    = uri;

            ReceiveTcs = new ReusableTaskCompletionSource <int> ();
            SendTcs    = new ReusableTaskCompletionSource <int> ();
        }
        public async Task StressTest_Reuse()
        {
            var tasks = new List <Task> ();

            for (int count = 0; count < Environment.ProcessorCount * 2; count++)
            {
                tasks.Add(Task.Run(async() => {
                    var tcs = new ReusableTaskCompletionSource <int>();
                    for (int i = 0; i < 50000; i++)
                    {
                        await Task.WhenAll(
                            Task.Run(() => { tcs.SetResult(111); }),
                            Task.Run(async() => {
                            var result = await tcs.Task;
                            Assert.AreEqual(111, result);
                        })
                            );
                    }
                }));
            }

            await Task.WhenAll(tasks);
        }
 public void NotInCache()
 {
     _ = new ReusableTaskCompletionSource <int> ();
     Assert.AreEqual(0, ReusableTaskMethodBuilder <int> .CacheCount, "#1");
 }
        async ReusableTask <bool> WaitForPendingWrites()
        {
            var tcs = new ReusableTaskCompletionSource <bool> ();

            WriteQueue.Enqueue(new BufferedIO(null, default, null, false, tcs));