diff --git a/src/System.IO.Pipelines/src/System.IO.Pipelines.csproj b/src/System.IO.Pipelines/src/System.IO.Pipelines.csproj index 4f81ddc17d57..dc6fc2604240 100644 --- a/src/System.IO.Pipelines/src/System.IO.Pipelines.csproj +++ b/src/System.IO.Pipelines/src/System.IO.Pipelines.csproj @@ -47,6 +47,7 @@ + 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 5a7ab3308c7d..d720c410aa4b 100644 --- a/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs +++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs @@ -43,9 +43,7 @@ public sealed partial class Pipe private readonly PipeScheduler _writerScheduler; private int _pooledSegmentCount; - private readonly BufferSegment[] _bufferSegmentPool; - // Temporary list to hold Segments return while being reset - private readonly BufferSegment[] _bufferSegmentsToReturn; + private readonly SegmentAsValue[] _bufferSegmentPool; private readonly DefaultPipeReader _reader; private readonly DefaultPipeWriter _writer; @@ -97,8 +95,7 @@ public Pipe(PipeOptions options) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.options); } - _bufferSegmentPool = new BufferSegment[SegmentPoolSize]; - _bufferSegmentsToReturn = new BufferSegment[SegmentPoolSize]; + _bufferSegmentPool = new SegmentAsValue[SegmentPoolSize]; _operationState = default; _readerCompletion = default; @@ -297,66 +294,6 @@ private int GetSegmentSize(int sizeHint, int maxBufferSize = int.MaxValue) return adjustedToMaximumSize; } - private BufferSegment CreateSegmentSynchronized() - { - BufferSegment[] segmentPool = _bufferSegmentPool; - lock (segmentPool) - { - int index = _pooledSegmentCount - 1; - if ((uint)index < (uint)segmentPool.Length) - { - _pooledSegmentCount = index; - return segmentPool[index]; - } - } - - return new BufferSegment(); - } - - private void ReturnSegments(BufferSegment from, BufferSegment toExclusive) - { - Debug.Assert(from != null); - Debug.Assert(from != toExclusive); - - // Reset the Segments and return their data out of lock - BufferSegment[] segmentToReturn = _bufferSegmentsToReturn; - int count = 0; - do - { - BufferSegment next = from.NextSegment; - Debug.Assert(next != null || toExclusive == null); - - from.ResetMemory(); - - if ((uint)count < (uint)segmentToReturn.Length) - { - // Store in temporary list while preforming expensive resets - segmentToReturn[count] = from; - count++; - } - - from = next; - } while (from != toExclusive); - - // Add the Segments back to pool from the temporary list under lock - BufferSegment[] segmentPool = _bufferSegmentPool; - lock (segmentPool) - { - int index = _pooledSegmentCount; - for (int i = 0; i < count; i++) - { - if ((uint)index < (uint)segmentPool.Length) - { - segmentPool[index] = segmentToReturn[i]; - index++; - } - segmentToReturn[i] = null; - } - - _pooledSegmentCount = index; - } - } - internal bool CommitUnsynchronized() { _operationState.EndWrite(); @@ -1115,5 +1052,93 @@ public void Reset() ResetState(); } } + + private BufferSegment CreateSegmentSynchronized() + { + SegmentAsValue[] segmentPool = _bufferSegmentPool; + lock (segmentPool) + { + int index = _pooledSegmentCount - 1; + if ((uint)index < (uint)segmentPool.Length) + { + _pooledSegmentCount = index; + return segmentPool[index]; + } + } + + return new BufferSegment(); + } + + private void ReturnSegments(BufferSegment from, BufferSegment toExclusive) + { + Debug.Assert(from != null); + Debug.Assert(from != toExclusive); + + // Reset the Segments and return their data out of lock + ValueSegmentList segmentsToReturn = default; + ref var startSegment = ref segmentsToReturn.Segment00; + int count = 0; + do + { + BufferSegment next = from.NextSegment; + Debug.Assert(next != null || toExclusive == null); + + from.ResetMemory(); + + if ((uint)count < (uint)SegmentPoolSize) + { + // Store in temporary list while preforming expensive resets + Unsafe.Add(ref startSegment, count) = from; + count++; + } + + from = next; + } while (from != toExclusive); + + // Add the Segments back to pool from the temporary list under lock + SegmentAsValue[] segmentPool = _bufferSegmentPool; + lock (segmentPool) + { + int index = _pooledSegmentCount; + for (int i = 0; i < count; i++) + { + if ((uint)index < (uint)segmentPool.Length) + { + segmentPool[index] = Unsafe.Add(ref startSegment, i); + index++; + } + } + + _pooledSegmentCount = index; + } + } + private readonly struct SegmentAsValue + { + private readonly BufferSegment _bufferSegment; + public SegmentAsValue(BufferSegment bufferSegment) => _bufferSegment = bufferSegment; + public static implicit operator SegmentAsValue(BufferSegment b) => new SegmentAsValue(b); + public static implicit operator BufferSegment(SegmentAsValue s) => s._bufferSegment; + } + + // Temporary list to hold Segments return while being reset + private ref struct ValueSegmentList + { + public BufferSegment Segment00; + public BufferSegment Segment01; + public BufferSegment Segment02; + public BufferSegment Segment03; + public BufferSegment Segment04; + public BufferSegment Segment05; + public BufferSegment Segment06; + public BufferSegment Segment07; + public BufferSegment Segment08; + public BufferSegment Segment09; + public BufferSegment Segment10; + public BufferSegment Segment11; + public BufferSegment Segment12; + public BufferSegment Segment13; + public BufferSegment Segment14; + public BufferSegment Segment15; + } } }