public void FlushAsyncReturnsNonCompletedSizeWhenCommitOverTheLimit() { PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64); PipeAwaiter <FlushResult> flushAsync = writableBuffer.FlushAsync(); Assert.False(flushAsync.IsCompleted); }
public async Task AdvanceEmptyBufferAfterWritingResetsAwaitable() { byte[] bytes = Encoding.ASCII.GetBytes("Hello World"); await _pipe.Writer.WriteAsync(bytes); ReadResult result = await _pipe.Reader.ReadAsync(); ReadOnlySequence <byte> buffer = result.Buffer; Assert.Equal(11, buffer.Length); Assert.True(buffer.IsSingleSegment); var array = new byte[11]; buffer.First.Span.CopyTo(array); Assert.Equal("Hello World", Encoding.ASCII.GetString(array)); _pipe.Reader.AdvanceTo(buffer.End); // Now write 0 and advance 0 await _pipe.Writer.WriteAsync(new byte[] { }); result = await _pipe.Reader.ReadAsync(); _pipe.Reader.AdvanceTo(result.Buffer.End); PipeAwaiter <ReadResult> awaitable = _pipe.Reader.ReadAsync(); Assert.False(awaitable.IsCompleted); }
public async Task EmptyBufferStartCrossingSegmentBoundaryIsTreatedLikeAndEnd() { Memory <byte> memory = _pipe.Writer.GetMemory(); // Append one full segment to a pipe _pipe.Writer.Write(memory.Span); _pipe.Writer.Commit(); await _pipe.Writer.FlushAsync(); // Consume entire segment ReadResult result = await _pipe.Reader.ReadAsync(); _pipe.Reader.AdvanceTo(result.Buffer.End); // Append empty segment _pipe.Writer.GetMemory(1); _pipe.Writer.Commit(); await _pipe.Writer.FlushAsync(); result = await _pipe.Reader.ReadAsync(); Assert.True(result.Buffer.IsEmpty); Assert.Equal(result.Buffer.Start, result.Buffer.End); _pipe.Writer.GetMemory(); _pipe.Reader.AdvanceTo(result.Buffer.Start); PipeAwaiter <ReadResult> awaitable = _pipe.Reader.ReadAsync(); Assert.False(awaitable.IsCompleted); _pipe.Writer.Commit(); }
public void FlushAsyncCancellationDeadlock() { var cts = new CancellationTokenSource(); var cts2 = new CancellationTokenSource(); var e = new ManualResetEventSlim(); PipeAwaiter <ReadResult> awaiter = Pipe.Reader.ReadAsync(cts.Token); awaiter.OnCompleted( () => { // We are on cancellation thread and need to wait untill another ReadAsync call // takes pipe state lock e.Wait(); // Make sure we had enough time to reach _cancellationTokenRegistration.Dispose Thread.Sleep(100); // Try to take pipe state lock Pipe.Reader.ReadAsync(); }); // Start a thread that would run cancellation calbacks Task cancellationTask = Task.Run(() => cts.Cancel()); // Start a thread that would call ReadAsync with different token // and block on _cancellationTokenRegistration.Dispose Task blockingTask = Task.Run( () => { e.Set(); Pipe.Reader.ReadAsync(cts2.Token); }); bool completed = Task.WhenAll(cancellationTask, blockingTask).Wait(TimeSpan.FromSeconds(10)); Assert.True(completed); }
public async Task CancellingBeforeAdvance() { byte[] bytes = Encoding.ASCII.GetBytes("Hello World"); PipeWriter output = Pipe.Writer; output.Write(bytes); await output.FlushAsync(); ReadResult result = await Pipe.Reader.ReadAsync(); ReadOnlySequence <byte> buffer = result.Buffer; Assert.Equal(11, buffer.Length); Assert.False(result.IsCanceled); Assert.True(buffer.IsSingleSegment); var array = new byte[11]; buffer.First.Span.CopyTo(array); Assert.Equal("Hello World", Encoding.ASCII.GetString(array)); Pipe.Reader.CancelPendingRead(); Pipe.Reader.AdvanceTo(buffer.End); PipeAwaiter <ReadResult> awaitable = Pipe.Reader.ReadAsync(); Assert.True(awaitable.IsCompleted); result = await awaitable; Assert.True(result.IsCanceled); Pipe.Reader.AdvanceTo(result.Buffer.Start, result.Buffer.Start); }
public async Task AdvanceResetsCommitHeadIndex() { _pipe.Writer.GetMemory(1); _pipe.Writer.Advance(100); await _pipe.Writer.FlushAsync(); // Advance to the end ReadResult readResult = await _pipe.Reader.ReadAsync(); _pipe.Reader.AdvanceTo(readResult.Buffer.End); // Try reading, it should block PipeAwaiter <ReadResult> awaitable = _pipe.Reader.ReadAsync(); Assert.False(awaitable.IsCompleted); // Unblock without writing anything _pipe.Writer.GetMemory(); await _pipe.Writer.FlushAsync(); Assert.True(awaitable.IsCompleted); // Advance to the end should reset awaitable readResult = await awaitable; _pipe.Reader.AdvanceTo(readResult.Buffer.End); // Try reading, it should block awaitable = _pipe.Reader.ReadAsync(); Assert.False(awaitable.IsCompleted); }
public void FlushAsyncReturnsCompletedTaskWhenSizeLessThenLimit() { PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(32); PipeAwaiter <FlushResult> flushAsync = writableBuffer.FlushAsync(); Assert.True(flushAsync.IsCompleted); FlushResult flushResult = flushAsync.GetResult(); Assert.False(flushResult.IsCompleted); }
public void FlushAsync_ReturnsCompletedTaskWhenMaxSizeIfZero() { PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(1); PipeAwaiter <FlushResult> flushTask = writableBuffer.FlushAsync(); Assert.True(flushTask.IsCompleted); writableBuffer = _pipe.Writer.WriteEmpty(1); flushTask = writableBuffer.FlushAsync(); Assert.True(flushTask.IsCompleted); }
public void FlushAsyncReturnsCanceledIfCancelledBeforeFlush() { PipeWriter writableBuffer = Pipe.Writer.WriteEmpty(MaximumSizeHigh); Pipe.Writer.CancelPendingFlush(); PipeAwaiter <FlushResult> flushAsync = writableBuffer.FlushAsync(); Assert.True(flushAsync.IsCompleted); FlushResult flushResult = flushAsync.GetResult(); Assert.True(flushResult.IsCanceled); }
public void FlushAsyncReturnsCompletedIfReaderCompletes() { PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64); PipeAwaiter <FlushResult> flushAsync = writableBuffer.FlushAsync(); Assert.False(flushAsync.IsCompleted); _pipe.Reader.Complete(); Assert.True(flushAsync.IsCompleted); FlushResult flushResult = flushAsync.GetResult(); Assert.True(flushResult.IsCompleted); }
public void FlushAsyncAwaitableDoesNotCompletesWhenReaderAdvancesUnderHight() { PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64); PipeAwaiter <FlushResult> flushAsync = writableBuffer.FlushAsync(); Assert.False(flushAsync.IsCompleted); ReadResult result = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); SequencePosition consumed = result.Buffer.GetPosition(32); _pipe.Reader.AdvanceTo(consumed, consumed); Assert.False(flushAsync.IsCompleted); }
private async Task ApplyBackpressureAsync(PipeAwaiter <FlushResult> flushTask) { Log.ConnectionPause(ConnectionId); _socket.ReadStop(); var result = await flushTask; // If the reader isn't complete or cancelled then resume reading if (!result.IsCompleted && !result.IsCanceled) { Log.ConnectionResume(ConnectionId); StartReading(); } }
public void AdvanceThrowsIfFlushActiveAndNotConsumedPastThreshold() { PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64); PipeAwaiter <FlushResult> flushAsync = writableBuffer.FlushAsync(); Assert.False(flushAsync.IsCompleted); ReadResult result = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); SequencePosition consumed = result.Buffer.GetPosition(31); Assert.Throws <InvalidOperationException>(() => _pipe.Reader.AdvanceTo(consumed, result.Buffer.End)); _pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End); }
private static async Task Continue(PipeAwaiter <FlushResult> awaitable, ReadOperation operation) { // Keep reading once we get the completion var flushResult = await awaitable; if (!flushResult.IsCompleted) { operation.Read(); } else { operation.Writer.Complete(); operation.Dispose(); } }
public void ReadAsyncReturnsIsCancelOnCancelPendingReadBeforeGetResult() { PipeAwaiter <ReadResult> awaitable = Pipe.Reader.ReadAsync(); Assert.False(awaitable.IsCompleted); awaitable.OnCompleted(() => { }); Pipe.Writer.WriteAsync(new byte[] { }); Pipe.Reader.CancelPendingRead(); Assert.True(awaitable.IsCompleted); ReadResult result = awaitable.GetResult(); Assert.True(result.IsCanceled); }
public void FlushAsyncReturnsIsCancelOnCancelPendingFlushBeforeGetResult() { PipeWriter writableBuffer = Pipe.Writer.WriteEmpty(MaximumSizeHigh); PipeAwaiter <FlushResult> awaitable = writableBuffer.FlushAsync(); Assert.False(awaitable.IsCompleted); awaitable.OnCompleted(() => { }); Pipe.Reader.AdvanceTo(Pipe.Reader.ReadAsync().GetResult().Buffer.End); Pipe.Writer.CancelPendingFlush(); Assert.True(awaitable.IsCompleted); FlushResult result = awaitable.GetResult(); Assert.True(result.IsCanceled); }
public void FlushAsyncCompletedAfterPreCancellation() { PipeWriter writableBuffer = Pipe.Writer.WriteEmpty(1); Pipe.Writer.CancelPendingFlush(); PipeAwaiter <FlushResult> flushAsync = writableBuffer.FlushAsync(); Assert.True(flushAsync.IsCompleted); FlushResult flushResult = flushAsync.GetResult(); Assert.True(flushResult.IsCanceled); flushAsync = writableBuffer.FlushAsync(); Assert.True(flushAsync.IsCompleted); }
public async Task AdvanceShouldResetStateIfReadCanceled() { Pipe.Reader.CancelPendingRead(); ReadResult result = await Pipe.Reader.ReadAsync(); ReadOnlySequence <byte> buffer = result.Buffer; Pipe.Reader.AdvanceTo(buffer.End); Assert.False(result.IsCompleted); Assert.True(result.IsCanceled); Assert.True(buffer.IsEmpty); PipeAwaiter <ReadResult> awaitable = Pipe.Reader.ReadAsync(); Assert.False(awaitable.IsCompleted); }
public async Task FlushCallbackRunsOnWriterScheduler() { using (var pool = new TestMemoryPool()) { using (var scheduler = new ThreadScheduler()) { var pipe = new Pipe( new PipeOptions( pool, resumeWriterThreshold: 32, pauseWriterThreshold: 64, readerScheduler: PipeScheduler.Inline, writerScheduler: scheduler)); PipeWriter writableBuffer = pipe.Writer.WriteEmpty(64); PipeAwaiter <FlushResult> flushAsync = writableBuffer.FlushAsync(); Assert.False(flushAsync.IsCompleted); Func <Task> doWrite = async() => { int oid = Thread.CurrentThread.ManagedThreadId; await flushAsync; Assert.NotEqual(oid, Thread.CurrentThread.ManagedThreadId); pipe.Writer.Complete(); Assert.Equal(Thread.CurrentThread.ManagedThreadId, scheduler.Thread.ManagedThreadId); }; Task writing = doWrite(); ReadResult result = await pipe.Reader.ReadAsync(); pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End); pipe.Reader.Complete(); await writing; } } }
public void GetResultThrowsIfReadAsyncCanceledBeforeOnCompleted() { var onCompletedCalled = false; var cancellationTokenSource = new CancellationTokenSource(); PipeAwaiter <ReadResult> awaiter = Pipe.Reader.ReadAsync(cancellationTokenSource.Token); bool awaiterIsCompleted = awaiter.IsCompleted; cancellationTokenSource.Cancel(); awaiter.OnCompleted( () => { onCompletedCalled = true; Assert.Throws <OperationCanceledException>(() => awaiter.GetResult()); }); Assert.False(awaiterIsCompleted); Assert.True(onCompletedCalled); }
public void ReadAsyncCompletedAfterPreCancellation() { Pipe.Reader.CancelPendingRead(); Pipe.Writer.WriteAsync(new byte[] { 1, 2, 3 }).GetAwaiter().GetResult(); PipeAwaiter <ReadResult> awaitable = Pipe.Reader.ReadAsync(); Assert.True(awaitable.IsCompleted); ReadResult result = awaitable.GetResult(); Assert.True(result.IsCanceled); awaitable = Pipe.Reader.ReadAsync(); Assert.True(awaitable.IsCompleted); Pipe.Reader.AdvanceTo(awaitable.GetResult().Buffer.End); }
public void GetResultThrowsIfFlushAsyncCancelledBeforeOnCompleted() { var onCompletedCalled = false; var cancellationTokenSource = new CancellationTokenSource(); PipeWriter buffer = Pipe.Writer.WriteEmpty(MaximumSizeHigh); PipeAwaiter <FlushResult> awaiter = buffer.FlushAsync(cancellationTokenSource.Token); bool awaiterIsCompleted = awaiter.IsCompleted; cancellationTokenSource.Cancel(); awaiter.OnCompleted( () => { onCompletedCalled = true; Assert.Throws <OperationCanceledException>(() => awaiter.GetResult()); }); Assert.False(awaiterIsCompleted); Assert.True(onCompletedCalled); }
private async Task FlushAsyncAwaited(PipeAwaiter <FlushResult> awaitable, CancellationToken cancellationToken) { // https://github.com/dotnet/corefxlab/issues/1334 // Since the flush awaitable doesn't currently support multiple awaiters // we need to use a task to track the callbacks. // All awaiters get the same task lock (_flushLock) { if (_flushTcs == null || _flushTcs.Task.IsCompleted) { _flushTcs = new TaskCompletionSource <object>(); awaitable.OnCompleted(_flushCompleted); } } await _flushTcs.Task; cancellationToken.ThrowIfCancellationRequested(); }
public void OnWriterCompletedRanBeforeReadContinuation() { var callbackRan = false; var continuationRan = false; var pipe = new Pipe(new PipeOptions(_pool)); pipe.Reader.OnWriterCompleted( (exception, state) => { callbackRan = true; Assert.False(continuationRan); }, null); PipeAwaiter <ReadResult> awaiter = pipe.Reader.ReadAsync(); Assert.False(awaiter.IsCompleted); awaiter.OnCompleted(() => { continuationRan = true; }); pipe.Writer.Complete(); Assert.True(callbackRan); }
public void AwaitingReadAsyncAwaitableTwiceCompletesWriterWithException() { async Task Await(PipeAwaiter <ReadResult> a) { await a; } PipeAwaiter <ReadResult> awaitable = Pipe.Reader.ReadAsync(); Task task1 = Await(awaitable); Task task2 = Await(awaitable); Assert.Equal(true, task1.IsCompleted); Assert.Equal(true, task1.IsFaulted); Assert.Equal("Concurrent reads or writes are not supported.", task1.Exception.InnerExceptions[0].Message); Assert.Equal(true, task2.IsCompleted); Assert.Equal(true, task2.IsFaulted); Assert.Equal("Concurrent reads or writes are not supported.", task2.Exception.InnerExceptions[0].Message); }
public void ReadAsyncNotCompletedAfterCancellationTokenCanceled() { var onCompletedCalled = false; var cts = new CancellationTokenSource(); PipeAwaiter <ReadResult> awaitable = Pipe.Reader.ReadAsync(cts.Token); Assert.False(awaitable.IsCompleted); awaitable.OnCompleted( () => { onCompletedCalled = true; Assert.True(awaitable.IsCompleted); Assert.Throws <OperationCanceledException>(() => awaitable.GetResult()); awaitable = Pipe.Reader.ReadAsync(); Assert.False(awaitable.IsCompleted); }); cts.Cancel(); Assert.True(onCompletedCalled); }
public void ReadAsyncNotCompletedAfterCancellation() { var onCompletedCalled = false; PipeAwaiter <ReadResult> awaitable = Pipe.Reader.ReadAsync(); Assert.False(awaitable.IsCompleted); awaitable.OnCompleted( () => { onCompletedCalled = true; Assert.True(awaitable.IsCompleted); ReadResult readResult = awaitable.GetResult(); Assert.True(readResult.IsCanceled); awaitable = Pipe.Reader.ReadAsync(); Assert.False(awaitable.IsCompleted); }); Pipe.Reader.CancelPendingRead(); Assert.True(onCompletedCalled); }
public async Task DefaultWriterSchedulerRunsOnThreadPool() { using (var pool = new TestMemoryPool()) { var pipe = new Pipe( new PipeOptions( pool, resumeWriterThreshold: 32, pauseWriterThreshold: 64 )); PipeWriter writableBuffer = pipe.Writer.WriteEmpty(64); PipeAwaiter <FlushResult> flushAsync = writableBuffer.FlushAsync(); Assert.False(flushAsync.IsCompleted); var id = 0; Func <Task> doWrite = async() => { await flushAsync; pipe.Writer.Complete(); Assert.True(Thread.CurrentThread.IsThreadPoolThread); }; Task writing = doWrite(); ReadResult result = await pipe.Reader.ReadAsync(); id = Thread.CurrentThread.ManagedThreadId; pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End); pipe.Reader.Complete(); await writing; } }
public void OnReaderCompletedRanBeforeFlushContinuation() { var callbackRan = false; var continuationRan = false; var pipe = new Pipe(new PipeOptions(_pool, pauseWriterThreshold: 5)); pipe.Writer.OnReaderCompleted( (exception, state) => { Assert.False(continuationRan); callbackRan = true; }, null); PipeWriter buffer = pipe.Writer.WriteEmpty(10); PipeAwaiter <FlushResult> awaiter = buffer.FlushAsync(); Assert.False(awaiter.IsCompleted); awaiter.OnCompleted(() => { continuationRan = true; }); pipe.Reader.Complete(); Assert.True(callbackRan); pipe.Writer.Complete(); }
public void FlushAsyncAwaitableResetsOnCommit() { PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64); PipeAwaiter <FlushResult> flushAsync = writableBuffer.FlushAsync(); Assert.False(flushAsync.IsCompleted); ReadResult result = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); SequencePosition consumed = result.Buffer.GetPosition(33); _pipe.Reader.AdvanceTo(consumed, consumed); Assert.True(flushAsync.IsCompleted); FlushResult flushResult = flushAsync.GetResult(); Assert.False(flushResult.IsCompleted); writableBuffer = _pipe.Writer.WriteEmpty(64); flushAsync = writableBuffer.FlushAsync(); Assert.False(flushAsync.IsCompleted); }