示例#1
0
        /// <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));
            }
        }
示例#2
0
 private void EnsureAlloc()
 {
     if (!_writingState.IsActive)
     {
         PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.NotWritingNoAlloc);
     }
 }
示例#3
0
        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
        }
示例#4
0
        /// <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);
 }
示例#7
0
 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);
 }
示例#9
0
        /// <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));
        }
示例#10
0
        /// <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));
        }
示例#11
0
        public override OwnedBuffer <byte> Rent(int size)
        {
            if (size > _blockLength)
            {
                PipelinesThrowHelper.ThrowArgumentOutOfRangeException_BufferRequestTooLarge(_blockLength);
            }

            var block = Lease();

            return(block);
        }
示例#12
0
        public void End(ExceptionResource exception)
        {
            if (_state == State.Inactive)
            {
                PipelinesThrowHelper.ThrowInvalidOperationException(exception, Location);
            }

            _state = State.Inactive;
#if OPERATION_LOCATION_TRACKING
            _operationStartLocation = null;
#endif
        }
示例#13
0
        /// <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);
            }
        }
示例#14
0
        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
        }
示例#15
0
        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);
        }
示例#16
0
        ReadResult IReadableBufferAwaiter.GetResult()
        {
            if (!_readerAwaitable.IsCompleted)
            {
                PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.GetResultNotCompleted);
            }

            var result = new ReadResult();

            lock (_sync)
            {
                GetResult(ref result);
            }
            return(result);
        }
示例#17
0
        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));
        }
示例#18
0
        /// <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));
        }
示例#19
0
        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);
            }
        }
示例#20
0
        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);
        }
示例#21
0
        // 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);
        }
示例#22
0
 public void Reset()
 {
     PipelinesThrowHelper.ThrowNotSupportedException();
 }