Exemplo n.º 1
0
        /// <summary>
        /// Writes a new buffer into the channel. The task returned by this operation only completes when the next
        /// Read has been queued, or the Reader has completed, since the buffer provided here needs to be kept alive
        /// until the matching Read finishes (because we don't have ownership tracking when working with unowned buffers)
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        // Called by the WRITER
        public async Task WriteAsync(OwnedMemory <byte> buffer, CancellationToken cancellationToken)
        {
            // If Writing has stopped, why is the caller writing??
            if (Writing.Status != TaskStatus.WaitingForActivation)
            {
                throw new OperationCanceledException("Writing has ceased on this Channel");
            }

            // If Reading has stopped, we cancel. We don't write unless there's a reader ready in this channel.
            if (Reading.Status != TaskStatus.WaitingForActivation)
            {
                throw new OperationCanceledException("Reading has ceased on this Channel");
            }

            // Register for cancellation on this token for the duration of the write
            using (cancellationToken.Register(state => ((UnownedBufferChannel)state).CancelWriter(), this))
            {
                // Wait for reading to start
                await ReadingStarted;

                // Cancel this task if this write is cancelled
                cancellationToken.ThrowIfCancellationRequested();

                // Allocate a new segment to hold the buffer being written.
                using (var segment = new BufferSegment(buffer))
                {
                    segment.End = buffer.Memory.Length;

                    if (_head == null || _head.ReadableBytes == 0)
                    {
                        // Update the head to point to the head of the buffer.
                        _head = segment;
                    }
                    else if (_tail != null)
                    {
                        // Add this segment to the end of the chain
                        _tail.Next = segment;
                    }

                    // Always update tail to the buffer's tail
                    _tail = segment;

                    // Trigger the continuation
                    Complete();

                    // Wait for another read to come (or for the end of Reading, which will also trigger this gate to open) in before returning
                    await _readWaiting;

                    if (_head.ReadableBytes > 0)
                    {
                        // We need to preserve any buffers that haven't been consumed
                        _head = BufferSegment.Clone(new ReadCursor(_head), new ReadCursor(_tail, _tail?.End ?? 0), out _tail);
                    }
                }

                // Cancel this task if this write is cancelled
                cancellationToken.ThrowIfCancellationRequested();
            }
        }
Exemplo n.º 2
0
        private ReadableBuffer(ref ReadableBuffer buffer)
        {
            var begin = buffer._start;
            var end   = buffer._end;

            BufferSegment segmentTail;
            var           segmentHead = BufferSegment.Clone(begin, end, out segmentTail);

            begin = new ReadCursor(segmentHead);
            end   = new ReadCursor(segmentTail, segmentTail.End);

            _start = begin;
            _end   = end;

            _length = buffer._length;

            begin.TryGetBuffer(end, out _first, out begin);
        }
Exemplo n.º 3
0
        private ReadableBuffer(ref ReadableBuffer buffer)
        {
            var begin = buffer._start;
            var end   = buffer._end;

            BufferSegment segmentTail;
            var           segmentHead = BufferSegment.Clone(begin, end, out segmentTail);

            begin = new ReadCursor(segmentHead);
            end   = new ReadCursor(segmentTail, segmentTail.End);

            _start   = begin;
            _end     = end;
            _isOwner = true;
            _first   = buffer._first;

            _length = buffer._length;
        }
Exemplo n.º 4
0
        internal void Append(ReadableBuffer buffer)
        {
            if (buffer.IsEmpty)
            {
                return; // nothing to do
            }

            EnsureAlloc();

            BufferSegment clonedEnd;
            var           clonedBegin = BufferSegment.Clone(buffer.Start, buffer.End, out clonedEnd);

            if (_writingHead == null)
            {
                // No active write

                if (_commitHead == null)
                {
                    // No allocated buffers yet, not locking as _readHead will be null
                    _commitHead = clonedBegin;
                }
                else
                {
                    Debug.Assert(_commitHead.Next == null);
                    // Allocated buffer, append as next segment
                    _commitHead.Next = clonedBegin;
                }
            }
            else
            {
                Debug.Assert(_writingHead.Next == null);
                // Active write, append as next segment
                _writingHead.Next = clonedBegin;
            }

            // Move write head to end of buffer
            _writingHead = clonedEnd;
        }