diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs index 264527db8332..90e18a452658 100644 --- a/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs +++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs @@ -264,6 +264,8 @@ private void ReturnSegments(BufferSegment from, BufferSegment toExclusive) do { BufferSegment next = from.NextSegment; + Debug.Assert(next != null || toExclusive == null); + from.ResetMemory(); if ((uint)index < (uint)segmentPool.Length) @@ -440,6 +442,7 @@ private void AdvanceReader(BufferSegment consumedSegment, int consumedIndex, Buf BufferSegment returnEnd = null; CompletionData completionData = default; + bool isReadComplete; lock (_sync) { @@ -517,15 +520,24 @@ private void AdvanceReader(BufferSegment consumedSegment, int consumedIndex, Buf _readerAwaitable.SetUncompleted(); } - _operationState.EndRead(); + isReadComplete = _operationState.TryEndRead(); } - TrySchedule(_writerScheduler, completionData); + if (isReadComplete) + { + TrySchedule(_writerScheduler, completionData); + } if (returnStart != null && returnStart != returnEnd) { ReturnSegments(returnStart, returnEnd); } + + if (!isReadComplete) + { + // Segments need to be returned (above) prior to the throw. + ThrowHelper.ThrowInvalidOperationException_NoReadToComplete(); + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeOperationState.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeOperationState.cs index e72560b05aa3..0dbffda9f76a 100644 --- a/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeOperationState.cs +++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeOperationState.cs @@ -46,6 +46,20 @@ public void EndRead() _state &= ~(State.Reading | State.ReadingTentative); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryEndRead() + { + if ((_state & State.Reading) != State.Reading && + (_state & State.ReadingTentative) != State.ReadingTentative) + { + return false; + } + + _state &= ~(State.Reading | State.ReadingTentative); + return true; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void BeginWrite() {