private static async Task FillRequest(PipeWriter writer, CancellationToken cancellation, Func <Memory <byte>, ValueTask <int> > write) { while (true) { var buffer = writer.GetMemory(); var bytesRead = await write(buffer); if (bytesRead == 0) { break; } writer.Advance(bytesRead); var result = await writer.FlushAsync(cancellation); if (result.IsCompleted) { break; } if (cancellation.IsCancellationRequested) { writer.CancelPendingFlush(); break; } } writer.Complete(); }
/// <summary> /// Closes this channel and releases all resources associated with it. /// Pending reads and writes may be abandoned if the channel was created with an <see cref="ChannelOptions.ExistingPipe"/>. /// </summary> /// <remarks> /// Because this method may terminate the channel immediately and thus can cause previously queued content to not actually be received by the remote party, /// consider this method a "break glass" way of terminating a channel. The preferred method is that both sides "complete writing" and let the channel dispose itself. /// </remarks> public void Dispose() { if (!this.IsDisposed) { // The code in this delegate needs to happen in several branches including possibly asynchronously. // We carefully define it here with no closure so that the C# compiler generates a static field for the delegate // thus avoiding any extra allocations from reusing code in this way. Action <object?, object> finalDisposalAction = (exOrAntecedent, state) => { var self = (Channel)state; self.completionSource.TrySetResult(null); self.MultiplexingStream.OnChannelDisposed(self); }; this.acceptanceSource.TrySetCanceled(); this.optionsAppliedTaskSource?.TrySetCanceled(); PipeWriter?mxStreamIOWriter; lock (this.SyncObject) { this.isDisposed = true; mxStreamIOWriter = this.mxStreamIOWriter; } // Complete writing so that the mxstream cannot write to this channel any more. // We must also cancel a pending flush since no one is guaranteed to be reading this any more // and we don't want to deadlock on a full buffer in a disposed channel's pipe. mxStreamIOWriter?.Complete(); mxStreamIOWriter?.CancelPendingFlush(); this.mxStreamIOWriterCompleted.Set(); if (this.channelIO != null) { // We're using our own Pipe to relay user messages, so we can shutdown writing and allow for our reader to propagate what was already written // before actually shutting down. this.channelIO.Output.Complete(); } else { // We don't own the user's PipeWriter to complete it (so they can't write anything more to this channel). // We can't know whether there is or will be more bytes written to the user's PipeWriter, // but we need to terminate our reader for their writer as part of reclaiming resources. // We want to complete reading immediately and cancel any pending read. this.mxStreamIOReader?.Complete(); this.mxStreamIOReader?.CancelPendingRead(); } // As a minor perf optimization, avoid allocating a continuation task if the antecedent is already completed. if (this.mxStreamIOReaderCompleted?.IsCompleted ?? true) { finalDisposalAction(null, this); } else { this.mxStreamIOReaderCompleted !.ContinueWith(finalDisposalAction, this, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default).Forget(); } } }
protected override void Dispose(bool disposing) { if (!disposing) { return; } _writer.CancelPendingFlush(); _writer.Complete(); _networkStream.Dispose(); }
public void CancelPendingFlush() { lock (_dataWriterLock) { if (_completed) { return; } _pipeWriter.CancelPendingFlush(); } }
public static async Task CopyToUntilCanceledOrCompletedAsync(this PipeReader reader, PipeWriter writer, CancellationToken cancel) { using var cancelRegistration = cancel.Register(delegate { // If we get canceled, indicate operation cancellation on both pipes to break out of the loop. // The purpose of this here is to avoid throwing exceptions for cancellation, instead using the graceful signal. // Just because exceptions cost extra CPU time that we want to avoid when handling load spikes (such as mass disconnects). reader.CancelPendingRead(); writer.CancelPendingFlush(); }); // We copy until we encounter either a read cancellation (upstream reached end of stream) or a write // completion (downstream reached end of stream) or a write cancellation (downstream requested graceful stop). while (true) { var readResult = await reader.ReadAsync(CancellationToken.None); if (readResult.IsCanceled) { break; } try { if (!readResult.Buffer.IsEmpty) { foreach (var segment in readResult.Buffer) { var memory = writer.GetMemory(segment.Length); segment.CopyTo(memory); writer.Advance(segment.Length); } var flushResult = await writer.FlushAsync(CancellationToken.None); if (flushResult.IsCanceled || flushResult.IsCompleted) { break; } } if (readResult.IsCompleted) { break; } } finally { reader.AdvanceTo(readResult.Buffer.End); } } }
public static void CancelPendingFlushEvenIfClosed(this PipeWriter writer) { // CancelPendingFlush() will throw if the pipe is already closed. // This behavior is not useful to us, so eat the exception. try { writer.CancelPendingFlush(); } catch { } }
private async Task CloseChannelAsync() { using (await _pipeLock.EnterAsync()) { try { _channelPipeWriter?.CancelPendingFlush(); _channelPipeWriter?.Complete(); _channelPipeWriter = null; } catch { // Ignore exceptions when trying to close a pipe } } }
public async Task CanCancelFlushAsyncWithCancelPendingFlushStreamWriteAsyncThrows() { var stream = new CancelledWritesStream(); stream.WaitForFlushTask.TrySetResult(null); PipeWriter writer = PipeWriter.Create(stream); writer.WriteEmpty(10); ValueTask <FlushResult> task = writer.FlushAsync(); Assert.False(task.IsCompleted); writer.CancelPendingFlush(); stream.WaitForWriteTask.TrySetResult(null); FlushResult result = await task; Assert.True(result.IsCanceled); writer.Complete(); }
public override void CancelPendingFlush() => _underlyingPipeWriter.CancelPendingFlush();
public override void CancelPendingFlush() => _writer.CancelPendingFlush();
public override void CancelPendingFlush() => _output.CancelPendingFlush();
public override void CancelPendingFlush() { _inner.CancelPendingFlush(); }
public void CancelPendingFlush() { _pipeWriter.CancelPendingFlush(); }
public override void CancelPendingFlush() { _pipeWriter.CancelPendingFlush(); }