internal ValueTask <FlushResult> FlushAsync(CancellationToken cancellationToken) { CompletionData completionData; CancellationTokenRegistration cancellationTokenRegistration; ValueTask <FlushResult> result; lock (_sync) { CommitUnsynchronized(); // AttachToken before completing reader awaiter in case cancellationToken is already completed cancellationTokenRegistration = _writerAwaitable.AttachToken(cancellationToken, s_signalWriterAwaitable, this); _readerAwaitable.Complete(out completionData); // If the writer is completed (which it will be most of the time) the return a completed ValueTask if (_writerAwaitable.IsCompleted) { var flushResult = new FlushResult(); GetFlushResult(ref flushResult); result = new ValueTask <FlushResult>(flushResult); } else { // Otherwise it's async result = new ValueTask <FlushResult>(_writer, token: 0); } } cancellationTokenRegistration.Dispose(); TrySchedule(_readerScheduler, completionData); return(result); }
internal ValueTask <FlushResult> FlushAsync(CancellationToken cancellationToken) { CompletionData completionData; CancellationTokenRegistration cancellationTokenRegistration; ValueTask <FlushResult> result; lock (_sync) { var wasEmpty = CommitUnsynchronized(); // AttachToken before completing reader awaiter in case cancellationToken is already completed cancellationTokenRegistration = _writerAwaitable.AttachToken(cancellationToken, s_signalWriterAwaitable, this); // If the writer is completed (which it will be most of the time) then return a completed ValueTask if (_writerAwaitable.IsCompleted) { var flushResult = new FlushResult(); GetFlushResult(ref flushResult); result = new ValueTask <FlushResult>(flushResult); } else { // Otherwise it's async result = new ValueTask <FlushResult>(_writer, token: 0); } // Complete reader only if new data was pushed into the pipe // Avoid throwing in between completing the reader and scheduling the callback // if the intent is to allow pipe to continue reading the data if (!wasEmpty) { _readerAwaitable.Complete(out completionData); } else { completionData = default; } // I couldn't find a way for flush to induce backpressure deadlock // if it always adds new data to pipe and wakes up the reader but assert anyway Debug.Assert(_writerAwaitable.IsCompleted || _readerAwaitable.IsCompleted); } cancellationTokenRegistration.Dispose(); TrySchedule(_readerScheduler, completionData); 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)); }
internal PipeAwaiter <ReadResult> ReadAsync(CancellationToken token) { CancellationTokenRegistration cancellationTokenRegistration; if (_readerCompletion.IsCompleted) { ThrowHelper.ThrowInvalidOperationException_NoReadingAllowed(); } lock (_sync) { cancellationTokenRegistration = _readerAwaitable.AttachToken(token, s_signalReaderAwaitable, this); } cancellationTokenRegistration.Dispose(); return(new PipeAwaiter <ReadResult>(_reader)); }
internal WritableBufferAwaitable FlushAsync(CancellationToken cancellationToken = default) { Action awaitable; CancellationTokenRegistration cancellationTokenRegistration; lock (_sync) { if (_writingState.IsActive) { // Commit the data as not already committed CommitUnsynchronized(); } awaitable = _readerAwaitable.Complete(); cancellationTokenRegistration = _writerAwaitable.AttachToken(cancellationToken, _signalWriterAwaitable, this); } cancellationTokenRegistration.Dispose(); TrySchedule(_readerScheduler, awaitable); return(new WritableBufferAwaitable(this)); }
internal PipeAwaiter <FlushResult> FlushAsync(CancellationToken cancellationToken) { Action awaitable; CancellationTokenRegistration cancellationTokenRegistration; lock (_sync) { if (_writingHead != null) { // Commit the data as not already committed CommitUnsynchronized(); } awaitable = _readerAwaitable.Complete(); cancellationTokenRegistration = _writerAwaitable.AttachToken(cancellationToken, s_signalWriterAwaitable, this); } cancellationTokenRegistration.Dispose(); TrySchedule(_readerScheduler, awaitable); return(new PipeAwaiter <FlushResult>(_writer)); }
internal ValueTask <FlushResult> FlushAsync(CancellationToken cancellationToken) { CompletionData completionData; CancellationTokenRegistration cancellationTokenRegistration; lock (_sync) { if (_writingHead != null) { // Commit the data as not already committed CommitUnsynchronized(); } _readerAwaitable.Complete(out completionData); cancellationTokenRegistration = _writerAwaitable.AttachToken(cancellationToken, s_signalWriterAwaitable, this); } cancellationTokenRegistration.Dispose(); TrySchedule(_readerScheduler, completionData); return(new ValueTask <FlushResult>(_writer, token: 0)); }