/// <summary> /// Allocates memory from the pipeline to write into. /// </summary> /// <param name="minimumSize">The minimum size buffer to allocate</param> /// <returns>A <see cref="WritableBuffer"/> that can be written to.</returns> WritableBuffer IPipeWriter.Alloc(int minimumSize) { if (_writerCompletion.IsCompleted) { PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.NoWritingAllowed, _writerCompletion.Location); } if (minimumSize < 0) { PipelinesThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.minimumSize); } lock (_sync) { // CompareExchange not required as its setting to current value if test fails _writingState.Begin(ExceptionResource.AlreadyWriting); if (minimumSize > 0) { try { AllocateWriteHeadUnsynchronized(minimumSize); } catch (Exception) { // Reset producing state if allocation failed _writingState.End(ExceptionResource.NoWriteToComplete); throw; } } _currentWriteLength = 0; return(new WritableBuffer(this)); } }
private void EnsureAlloc() { if (!_writingState.IsActive) { PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.NotWritingNoAlloc); } }
internal void AdvanceWriter(int bytesWritten) { EnsureAlloc(); if (bytesWritten > 0) { if (_writingHead == null) { PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.AdvancingWithNoBuffer); } Debug.Assert(!_writingHead.ReadOnly); Debug.Assert(_writingHead.Next == null); var buffer = _writingHead.Buffer; var bufferIndex = _writingHead.End + bytesWritten; if (bufferIndex > buffer.Length) { PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.AdvancingPastBufferSize); } _writingHead.End = bufferIndex; _currentWriteLength += bytesWritten; } else if (bytesWritten < 0) { PipelinesThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.bytesWritten); } // and if zero, just do nothing; don't need to validate tail etc }
/// <summary> /// Signal to the producer that the consumer is done reading. /// </summary> /// <param name="exception">Optional Exception indicating a failure that's causing the pipeline to complete.</param> void IPipeReader.Complete(Exception exception) { if (_readingState.IsActive) { PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.CompleteReaderActiveReader, _readingState.Location); } PipeCompletionCallbacks completionCallbacks; Action awaitable; bool writerCompleted; lock (_sync) { completionCallbacks = _readerCompletion.TryComplete(exception); awaitable = _writerAwaitable.Complete(); writerCompleted = _writerCompletion.IsCompleted; } if (completionCallbacks != null) { TrySchedule(_writerScheduler, _invokeCompletionCallbacks, completionCallbacks); } TrySchedule(_writerScheduler, awaitable); if (writerCompleted) { Dispose(); } }
public void Skip(int length) { if (length < 0) { PipelinesThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length); } _consumedBytes += length; while (!_end && length > 0) { if ((_index + length) < _currentSpan.Length) { _index += length; length = 0; break; } length -= (_currentSpan.Length - _index); MoveNext(); } if (length > 0) { PipelinesThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length); } }
protected override unsafe bool TryGetPointerInternal(out void *pointer) { if (IsDisposed) { PipelinesThrowHelper.ThrowObjectDisposedException(nameof(MemoryPoolBlock)); } pointer = (Slab.NativePointer + _offset).ToPointer(); return(true); }
protected override bool TryGetArrayInternal(out ArraySegment <byte> buffer) { if (IsDisposed) { PipelinesThrowHelper.ThrowObjectDisposedException(nameof(UnownedBuffer)); } buffer = _buffer; return(true); }
protected override bool TryGetArrayInternal(out ArraySegment <byte> buffer) { if (IsDisposed) { PipelinesThrowHelper.ThrowObjectDisposedException(nameof(MemoryPoolBlock)); } buffer = new ArraySegment <byte>(Slab.Array, _offset, _length); return(true); }
/// <summary> /// Create a <see cref="ReadableBuffer"/> over an array. /// </summary> public static ReadableBuffer Create(byte[] data) { if (data == null) { PipelinesThrowHelper.ThrowArgumentNullException(ExceptionArgument.data); } OwnedBuffer <byte> buffer = data; return(CreateInternal(buffer, 0, data.Length)); }
/// <summary> /// Create a <see cref="ReadableBuffer"/> over an array. /// </summary> public static ReadableBuffer Create(byte[] data, int offset, int length) { if (data == null) { PipelinesThrowHelper.ThrowArgumentNullException(ExceptionArgument.data); } OwnedBuffer <byte> buffer = data; return(Create(buffer, offset, length)); }
public override OwnedBuffer <byte> Rent(int size) { if (size > _blockLength) { PipelinesThrowHelper.ThrowArgumentOutOfRangeException_BufferRequestTooLarge(_blockLength); } var block = Lease(); return(block); }
public void End(ExceptionResource exception) { if (_state == State.Inactive) { PipelinesThrowHelper.ThrowInvalidOperationException(exception, Location); } _state = State.Inactive; #if OPERATION_LOCATION_TRACKING _operationStartLocation = null; #endif }
/// <summary> /// Copy the <see cref="ReadableBuffer"/> to the specified <see cref="Span{Byte}"/>. /// </summary> /// <param name="destination">The destination <see cref="Span{Byte}"/>.</param> public void CopyTo(Span <byte> destination) { if (Length > destination.Length) { PipelinesThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.destination); } foreach (var buffer in this) { buffer.Span.CopyTo(destination); destination = destination.Slice(buffer.Length); } }
public void BeginTentative(ExceptionResource exception) { // Inactive and Tenative are allowed if (_state == State.Active) { PipelinesThrowHelper.ThrowInvalidOperationException(exception, Location); } _state = State.Tentative; #if OPERATION_LOCATION_TRACKING _operationStartLocation = Environment.StackTrace; #endif }
void IWritableBufferAwaiter.OnCompleted(Action continuation) { Action awaitable; bool doubleCompletion; lock (_sync) { awaitable = _writerAwaitable.OnCompleted(continuation, out doubleCompletion); } if (doubleCompletion) { Reader.Complete(PipelinesThrowHelper.GetInvalidOperationException(ExceptionResource.NoConcurrentOperation)); } TrySchedule(_writerScheduler, awaitable); }
ReadResult IReadableBufferAwaiter.GetResult() { if (!_readerAwaitable.IsCompleted) { PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.GetResultNotCompleted); } var result = new ReadResult(); lock (_sync) { GetResult(ref result); } return(result); }
ReadableBufferAwaitable IPipeReader.ReadAsync(CancellationToken token) { CancellationTokenRegistration cancellationTokenRegistration; if (_readerCompletion.IsCompleted) { PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.NoReadingAllowed, _readerCompletion.Location); } lock (_sync) { cancellationTokenRegistration = _readerAwaitable.AttachToken(token, _signalReaderAwaitable, this); } cancellationTokenRegistration.Dispose(); return(new ReadableBufferAwaitable(this)); }
/// <summary> /// Create a <see cref="ReadableBuffer"/> over an OwnedBuffer. /// </summary> public static ReadableBuffer Create(OwnedBuffer <byte> data, int offset, int length) { if (data == null) { PipelinesThrowHelper.ThrowArgumentNullException(ExceptionArgument.data); } if (offset < 0) { PipelinesThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.offset); } if (length < 0 || length > data.Length - offset) { PipelinesThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length); } return(CreateInternal(data, offset, length)); }
bool IPipeReader.TryRead(out ReadResult result) { lock (_sync) { if (_readerCompletion.IsCompleted) { PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.NoReadingAllowed, _readerCompletion.Location); } result = new ReadResult(); if (_length > 0 || _readerAwaitable.IsCompleted) { GetResult(ref result); return(true); } if (_readerAwaitable.HasContinuation) { PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.AlreadyReading); } return(false); } }
FlushResult IWritableBufferAwaiter.GetResult() { var result = new FlushResult(); lock (_sync) { if (!_writerAwaitable.IsCompleted) { PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.GetResultNotCompleted); } // Change the state from to be cancelled -> observed if (_writerAwaitable.ObserveCancelation()) { result.ResultFlags |= ResultFlags.Cancelled; } if (_readerCompletion.IsCompletedOrThrow()) { result.ResultFlags |= ResultFlags.Completed; } } return(result); }
// Reading void IPipeReader.Advance(ReadCursor consumed, ReadCursor examined) { BufferSegment returnStart = null; BufferSegment returnEnd = null; // Reading commit head shared with writer Action continuation = null; lock (_sync) { var examinedEverything = examined.Segment == _commitHead && examined.Index == _commitHeadIndex; if (!consumed.IsDefault) { if (_readHead == null) { PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.AdvanceToInvalidCursor); return; } returnStart = _readHead; returnEnd = consumed.Segment; // Check if we crossed _maximumSizeLow and complete backpressure var consumedBytes = ReadCursor.GetLength(returnStart, returnStart.Start, consumed.Segment, consumed.Index); var oldLength = _length; _length -= consumedBytes; if (oldLength >= _maximumSizeLow && _length < _maximumSizeLow) { continuation = _writerAwaitable.Complete(); } // Check if we consumed entire last segment // if we are going to return commit head // we need to check that there is no writing operation that // might be using tailspace if (consumed.Index == returnEnd.End && !(_commitHead == returnEnd && _writingState.IsActive)) { var nextBlock = returnEnd.Next; if (_commitHead == returnEnd) { _commitHead = nextBlock; _commitHeadIndex = nextBlock?.Start ?? 0; } _readHead = nextBlock; returnEnd = nextBlock; } else { _readHead = consumed.Segment; _readHead.Start = consumed.Index; } } // We reset the awaitable to not completed if we've examined everything the producer produced so far // but only if writer is not completed yet if (examinedEverything && !_writerCompletion.IsCompleted) { // Prevent deadlock where reader awaits new data and writer await backpressure if (!_writerAwaitable.IsCompleted) { PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.BackpressureDeadlock); } _readerAwaitable.Reset(); } _readingState.End(ExceptionResource.NoReadToComplete); } while (returnStart != null && returnStart != returnEnd) { returnStart.Dispose(); returnStart = returnStart.Next; } TrySchedule(_writerScheduler, continuation); }
public void Reset() { PipelinesThrowHelper.ThrowNotSupportedException(); }