| File: System\IO\Pipelines\PipeOptions.cs | Web Access |
| Project: src\runtime\src\libraries\System.IO.Pipelines\src\System.IO.Pipelines.csproj (System.IO.Pipelines) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Buffers; using System.Threading; namespace System.IO.Pipelines { /// <summary>Represents a set of <see cref="System.IO.Pipelines.Pipe" /> options.</summary> public class PipeOptions { private const int DefaultMinimumSegmentSize = 4096; /// <summary>Gets the default instance of <see cref="System.IO.Pipelines.PipeOptions" />.</summary> /// <value>A <see cref="System.IO.Pipelines.PipeOptions" /> object initialized with default parameters.</value> public static PipeOptions Default { get; } = new PipeOptions(); /// <summary>Initializes a new instance of the <see cref="System.IO.Pipelines.PipeOptions" /> class with the specified parameters.</summary> /// <param name="pool">The pool of memory blocks to be used for buffer management.</param> /// <param name="readerScheduler">The <see cref="System.IO.Pipelines.PipeScheduler" /> to be used to execute <see cref="System.IO.Pipelines.PipeReader" /> callbacks and async continuations.</param> /// <param name="writerScheduler">The <see cref="System.IO.Pipelines.PipeScheduler" /> used to execute <see cref="System.IO.Pipelines.PipeWriter" /> callbacks and async continuations.</param> /// <param name="pauseWriterThreshold">The number of bytes in the <see cref="System.IO.Pipelines.Pipe" /> before <see cref="System.IO.Pipelines.PipeWriter.FlushAsync(System.Threading.CancellationToken)" /> starts blocking. A value of zero prevents <see cref="System.IO.Pipelines.PipeWriter.FlushAsync(System.Threading.CancellationToken)" /> from ever blocking, effectively making the number of bytes in the <see cref="System.IO.Pipelines.Pipe" /> unlimited.</param> /// <param name="resumeWriterThreshold">The number of bytes in the <see cref="System.IO.Pipelines.Pipe" /> when <see cref="System.IO.Pipelines.PipeWriter.FlushAsync(System.Threading.CancellationToken)" /> stops blocking.</param> /// <param name="minimumSegmentSize">The minimum size of the segment requested from <paramref name="pool" />.</param> /// <param name="useSynchronizationContext"><see langword="true" /> if asynchronous continuations should be executed on the <see cref="System.Threading.SynchronizationContext" /> they were captured on; <see langword="false" /> otherwise. This takes precedence over the schedulers specified in <see cref="System.IO.Pipelines.PipeOptions.ReaderScheduler" /> and <see cref="System.IO.Pipelines.PipeOptions.WriterScheduler" />.</param> public PipeOptions( MemoryPool<byte>? pool = null, PipeScheduler? readerScheduler = null, PipeScheduler? writerScheduler = null, long pauseWriterThreshold = -1, long resumeWriterThreshold = -1, int minimumSegmentSize = -1, bool useSynchronizationContext = true) { MinimumSegmentSize = minimumSegmentSize == -1 ? DefaultMinimumSegmentSize : minimumSegmentSize; // Cap the per-pipe segment-object pool to bound memory in edge cases. // Buffers are returned to the MemoryPool on Reset() before a segment is pooled, so a // pooled BufferSegment holds no bytes buffers and itself is ~96 bytes on 64-bit. // The cap therefore costs at most ~24 KB per pipe (256 * ~96 bytes); // the backing memory is pooled separately. // // Normal pipes never approach this cap. The pool only grows to the peak number of // simultaneously-live segments, which for a throttled pipe is roughly // PauseWriterThreshold / MinimumSegmentSize - with the defaults that is // 64 KB / 4 KB = ~16 segments. Reaching 256 requires either a very large // PauseWriterThreshold (>= 256 * MinimumSegmentSize, e.g. 1 MB of unconsumed data at // 4 KB segments) or an unbounded pipe (pauseWriterThreshold: 0) whose producer // consistently outruns the consumer. MaxSegmentPoolSize = 256; // By default, we'll throttle the writer at 64K of buffered data const int DefaultPauseWriterThreshold = 65536; // Resume threshold is 1/2 of the pause threshold to prevent thrashing at the limit const int DefaultResumeWriterThreshold = DefaultPauseWriterThreshold / 2; if (pauseWriterThreshold == -1) { pauseWriterThreshold = DefaultPauseWriterThreshold; } else if (pauseWriterThreshold < 0) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.pauseWriterThreshold); } if (resumeWriterThreshold == -1) { resumeWriterThreshold = DefaultResumeWriterThreshold; } else if (resumeWriterThreshold == 0) { // A resumeWriterThreshold of 0 makes no sense because the writer could never resume if paused. // By setting it to 1, the writer will resume only after all data is consumed. resumeWriterThreshold = 1; } // Only validate that the resumeWriterThreshold is not too large if the writer could actually pause. if (resumeWriterThreshold < 0 || (pauseWriterThreshold > 0 && resumeWriterThreshold > pauseWriterThreshold)) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.resumeWriterThreshold); } Pool = pool ?? MemoryPool<byte>.Shared; IsDefaultSharedMemoryPool = Pool == MemoryPool<byte>.Shared; ReaderScheduler = readerScheduler ?? PipeScheduler.ThreadPool; WriterScheduler = writerScheduler ?? PipeScheduler.ThreadPool; PauseWriterThreshold = pauseWriterThreshold; ResumeWriterThreshold = resumeWriterThreshold; UseSynchronizationContext = useSynchronizationContext; } /// <summary>Gets a value that determines if asynchronous callbacks and continuations should be executed on the <see cref="System.Threading.SynchronizationContext" /> they were captured on. This takes precedence over the schedulers specified in <see cref="System.IO.Pipelines.PipeOptions.ReaderScheduler" /> and <see cref="System.IO.Pipelines.PipeOptions.WriterScheduler" />.</summary> /// <value><see langword="true" /> if asynchronous callbacks and continuations should be executed on the <see cref="System.Threading.SynchronizationContext" /> they were captured on; otherwise, <see langword="false" />.</value> public bool UseSynchronizationContext { get; } /// <summary>Gets the number of bytes in the <see cref="System.IO.Pipelines.Pipe" /> when <see cref="System.IO.Pipelines.PipeWriter.FlushAsync(System.Threading.CancellationToken)" /> starts blocking.</summary> /// <value>The number of bytes in the <see cref="System.IO.Pipelines.Pipe" /> when <see cref="System.IO.Pipelines.PipeWriter.FlushAsync(System.Threading.CancellationToken)" /> starts blocking.</value> public long PauseWriterThreshold { get; } /// <summary>Gets the number of bytes in the <see cref="System.IO.Pipelines.Pipe" /> when <see cref="System.IO.Pipelines.PipeWriter.FlushAsync(System.Threading.CancellationToken)" /> stops blocking.</summary> /// <value>The number of bytes in the <see cref="System.IO.Pipelines.Pipe" /> when <see cref="System.IO.Pipelines.PipeWriter.FlushAsync(System.Threading.CancellationToken)" /> stops blocking.</value> public long ResumeWriterThreshold { get; } /// <summary>Gets the minimum size of the segment requested from the <see cref="System.IO.Pipelines.PipeOptions.Pool" />.</summary> /// <value>The minimum size of the segment requested from the <see cref="System.IO.Pipelines.PipeOptions.Pool" />.</value> public int MinimumSegmentSize { get; } /// <summary>Gets the <see cref="System.IO.Pipelines.PipeScheduler" /> used to execute <see cref="System.IO.Pipelines.PipeWriter" /> callbacks and async continuations.</summary> /// <value>A <see cref="System.IO.Pipelines.PipeScheduler" /> object used to execute <see cref="System.IO.Pipelines.PipeWriter" /> callbacks and async continuations.</value> public PipeScheduler WriterScheduler { get; } /// <summary>Gets the <see cref="System.IO.Pipelines.PipeScheduler" /> used to execute <see cref="System.IO.Pipelines.PipeReader" /> callbacks and async continuations.</summary> /// <value>A <see cref="System.IO.Pipelines.PipeScheduler" /> that is used to execute <see cref="System.IO.Pipelines.PipeReader" /> callbacks and async continuations.</value> public PipeScheduler ReaderScheduler { get; } /// <summary>Gets the <see cref="System.Buffers.MemoryPool{T}" /> object used for buffer management.</summary> /// <value>A pool of memory blocks used for buffer management.</value> public MemoryPool<byte> Pool { get; } /// <summary> /// Returns true if Pool is <see cref="MemoryPool{Byte}"/>.Shared /// </summary> internal bool IsDefaultSharedMemoryPool { get; } /// <summary> /// The maximum number of segments to pool /// </summary> internal int MaxSegmentPoolSize { get; } } }