public override async ValueTask <int> ReadAsync(Memory <byte> buffer, CancellationToken cancellationToken) { CancellationHelper.ThrowIfCancellationRequested(cancellationToken); if (_connection == null || buffer.Length == 0) { // Response body fully consumed or the caller didn't ask for any data return(0); } Debug.Assert(_contentBytesRemaining > 0); if ((ulong)buffer.Length > _contentBytesRemaining) { buffer = buffer.Slice(0, (int)_contentBytesRemaining); } ValueTask <int> readTask = _connection.ReadAsync(buffer); int bytesRead; if (readTask.IsCompletedSuccessfully) { bytesRead = readTask.Result; } else { CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken); try { bytesRead = await readTask.ConfigureAwait(false); } catch (Exception exc) when(CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken)) { throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken); } finally { ctr.Dispose(); } } if (bytesRead <= 0) { // A cancellation request may have caused the EOF. CancellationHelper.ThrowIfCancellationRequested(cancellationToken); // Unexpected end of response stream. throw new IOException(SR.Format(SR.net_http_invalid_response_premature_eof_bytecount, _contentBytesRemaining)); } Debug.Assert((ulong)bytesRead <= _contentBytesRemaining); _contentBytesRemaining -= (ulong)bytesRead; if (_contentBytesRemaining == 0) { // End of response body if (HttpTelemetry.Log.IsEnabled()) { LogRequestStop(); } _connection.CompleteResponse(); _connection = null; } return(bytesRead); }
/// <summary> /// Make a task execute synchronously /// </summary> /// <param name="task">Task</param> public static void Sync(this ValueTask task) { task.ConfigureAwait(false).GetAwaiter().GetResult(); }
static async Task <TiffInkSet> TransformValueTaskAsync(ValueTask <TiffValueCollection <ushort> > valueTask) { TiffValueCollection <ushort> result = await valueTask.ConfigureAwait(false); return(result.IsEmpty ? TiffInkSet.CMYK : (TiffInkSet)result.GetFirstOrDefault()); }
async ValueTask ConditionalExpression(int x, ValueTask <int> vt) { return(x > 3 ? await vt : await vt.ConfigureAwait(false)); }
public static ConfiguredValueTaskAwaitable <T> Ignore <T>(this ValueTask <T> task) => task.ConfigureAwait(false);
public async Task Reader_ContinuesOnCurrentTaskSchedulerIfDesired( bool readOrWait, bool completeBeforeOnCompleted, bool flowExecutionContext, bool?continueOnCapturedContext) { if (AllowSynchronousContinuations) { return; } await Task.Run(async() => { Assert.Null(SynchronizationContext.Current); Channel <bool> c = CreateChannel <bool>(); ValueTask <bool> vt = readOrWait ? c.Reader.ReadAsync() : c.Reader.WaitToReadAsync(); var continuationRan = new TaskCompletionSource <bool>(); var asyncLocal = new AsyncLocal <int>(); bool schedulerWasFlowed = false; bool executionContextWasFlowed = false; Action continuation = () => { schedulerWasFlowed = TaskScheduler.Current is CustomTaskScheduler; executionContextWasFlowed = 42 == asyncLocal.Value; continuationRan.SetResult(true); }; if (completeBeforeOnCompleted) { Assert.False(vt.IsCompleted); Assert.False(vt.IsCompletedSuccessfully); c.Writer.TryWrite(true); } await Task.Factory.StartNew(() => { Assert.IsType <CustomTaskScheduler>(TaskScheduler.Current); asyncLocal.Value = 42; switch (continueOnCapturedContext) { case null: if (flowExecutionContext) { vt.GetAwaiter().OnCompleted(continuation); } else { vt.GetAwaiter().UnsafeOnCompleted(continuation); } break; default: if (flowExecutionContext) { vt.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(continuation); } else { vt.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().UnsafeOnCompleted(continuation); } break; } asyncLocal.Value = 0; }, CancellationToken.None, TaskCreationOptions.None, new CustomTaskScheduler()); if (!completeBeforeOnCompleted) { Assert.False(vt.IsCompleted); Assert.False(vt.IsCompletedSuccessfully); c.Writer.TryWrite(true); } await continuationRan.Task; Assert.True(vt.IsCompleted); Assert.True(vt.IsCompletedSuccessfully); Assert.Equal(continueOnCapturedContext != false, schedulerWasFlowed); if (completeBeforeOnCompleted) // OnCompleted will simply queue using a mechanism that happens to flow { Assert.True(executionContextWasFlowed); } else { Assert.Equal(flowExecutionContext, executionContextWasFlowed); } }); }
public static async ValueTask <ISourceStream> AwaitValueTaskSourceStreamGeneric <T>( ValueTask <ISourceStream <T> > task) { return(await task.ConfigureAwait(false)); }
private static async Task WriteMessageCore(ValueTask writeMessageTask) { await writeMessageTask.ConfigureAwait(false); GrpcEventSource.Log.MessageSent(); }
static async IAsyncEnumerable <TSource> Core(IAsyncEnumerable <TSource>[] sources, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default) #if USE_FAIR_AND_CHEAPER_MERGE // // This new implementation of Merge differs from the original one in a few ways: // // - It's cheaper because: // - no conversion from ValueTask<bool> to Task<bool> takes place using AsTask, // - we don't instantiate Task.WhenAny tasks for each iteration. // - It's fairer because: // - the MoveNextAsync tasks are awaited concurently, but completions are queued, // instead of awaiting a new WhenAny task where "left" sources have preferential // treatment over "right" sources. // { var count = sources.Length; var enumerators = new IAsyncEnumerator <TSource> [count]; var moveNextTasks = new ValueTask <bool> [count]; try { for (var i = 0; i < count; i++) { IAsyncEnumerator <TSource> enumerator = sources[i].GetAsyncEnumerator(cancellationToken); enumerators[i] = enumerator; // REVIEW: This follows the lead of the original implementation where we kick off MoveNextAsync // operations immediately. An alternative would be to do this in a separate stage, thus // preventing concurrency across MoveNextAsync and GetAsyncEnumerator calls and avoiding // any MoveNextAsync calls before all enumerators are acquired (or an exception has // occurred doing so). moveNextTasks[i] = enumerator.MoveNextAsync(); } var whenAny = TaskExt.WhenAny(moveNextTasks); int active = count; while (active > 0) { int index = await whenAny; IAsyncEnumerator <TSource> enumerator = enumerators[index]; ValueTask <bool> moveNextTask = moveNextTasks[index]; if (!await moveNextTask.ConfigureAwait(false)) { // // Replace the task in our array by a completed task to make finally logic easier. Note that // the WhenAnyValueTask object has a reference to our array (i.e. no copy is made), so this // gets rid of any resources the original task may have held onto. However, we *don't* call // whenAny.Replace to set this value, because it'd attach an awaiter to the already completed // task, causing spurious wake-ups when awaiting whenAny. // moveNextTasks[index] = new ValueTask <bool>(); // REVIEW: The original implementation did not dispose eagerly, which could lead to resource // leaks when merged with other long-running sequences. enumerators[index] = null; // NB: Avoids attempt at double dispose in finally if disposing fails. await enumerator.DisposeAsync().ConfigureAwait(false); active--; } else { TSource item = enumerator.Current; // // Replace the task using whenAny.Replace, which will write it to the moveNextTasks array, and // will start awaiting the task. Note we don't have to write to moveNextTasks ourselves because // the whenAny object has a reference to it (i.e. no copy is made). // whenAny.Replace(index, enumerator.MoveNextAsync()); yield return(item); } } } finally { // REVIEW: The original implementation performs a concurrent dispose, which seems undesirable given the // additional uncontrollable source of concurrency and the sequential resource acquisition. In // this modern implementation, we release resources in opposite order as we acquired them, thus // guaranteeing determinism (and mimicking a series of nested `await using` statements). // REVIEW: If we decide to phase GetAsyncEnumerator and the initial MoveNextAsync calls at the start of // the operator implementation, we should make this symmetric and first await all in flight // MoveNextAsync operations, prior to disposing the enumerators. var errors = default(List <Exception>); for (var i = count - 1; i >= 0; i--) { ValueTask <bool> moveNextTask = moveNextTasks[i]; IAsyncEnumerator <TSource> enumerator = enumerators[i]; try { try { // // Await the task to ensure outstanding work is completed prior to performing a dispose // operation. Note that we don't have to do anything special for tasks belonging to // enumerators that have finished; we swapped in a placeholder completed task. // // REVIEW: This adds an additional continuation to all of the pending tasks (note that // whenAny also has registered one). The whenAny object will be collectible // after all of these complete. Alternatively, we could drain via whenAny, by // awaiting it until the active count drops to 0. This saves on attaching the // additional continuations, but we need to decide on order of dispose. Right // now, we dispose in opposite order of acquiring the enumerators, with the // exception of enumerators that were disposed eagerly upon early completion. // Should we care about the dispose order at all? _ = await moveNextTask.ConfigureAwait(false); } finally { if (enumerator != null) { await enumerator.DisposeAsync().ConfigureAwait(false); } } } catch (Exception ex) { if (errors == null) { errors = new List <Exception>(); } errors.Add(ex); } } // NB: If we had any errors during cleaning (and awaiting pending operations), we throw these exceptions // instead of the original exception that may have led to running the finally block. This is similar // to throwing from any finally block (except that we catch all exceptions to ensure cleanup of all // concurrent sequences being merged). if (errors != null) { throw new AggregateException(errors); } } }
private static async ValueTask <IAsyncDbTransaction> WrapValue <TTransaction>(ValueTask <TTransaction> transaction) where TTransaction : IDbTransaction { return(Create(await transaction.ConfigureAwait(Common.Configuration.ContinueOnCapturedContext))); }
public async Task ConfiguredAwaiter_ContinuesOnCapturedContext(bool continueOnCapturedContext) { await Task.Run(() => { var tsc = new TrackingSynchronizationContext(); SynchronizationContext.SetSynchronizationContext(tsc); try { ValueTask<int> t = new ValueTask<int>(42); var mres = new ManualResetEventSlim(); t.ConfigureAwait(continueOnCapturedContext).GetAwaiter().OnCompleted(() => mres.Set()); Assert.True(mres.Wait(10000)); Assert.Equal(continueOnCapturedContext ? 1 : 0, tsc.Posts); } finally { SynchronizationContext.SetSynchronizationContext(null); } }); }
public async Task ConfiguredAwaiter_OnCompleted(bool continueOnCapturedContext) { // Since ValueTask implements both OnCompleted and UnsafeOnCompleted, // OnCompleted typically won't be used by await, so we add an explicit test // for it here. ValueTask<int> t = new ValueTask<int>(42); var tcs = new TaskCompletionSource<bool>(); t.ConfigureAwait(continueOnCapturedContext).GetAwaiter().OnCompleted(() => tcs.SetResult(true)); await tcs.Task; }
private async ValueTask <int> FinishReadAsyncMemory( ValueTask <int> readTask, Memory <byte> buffer, CancellationToken cancellationToken) { try { Debug.Assert(_inflater != null && _buffer != null); while (true) { if (_inflater.NeedsInput()) { int bytesRead = await readTask.ConfigureAwait(false); EnsureNotDisposed(); if (bytesRead <= 0) { // This indicates the base stream has received EOF return(0); } else if (bytesRead > _buffer.Length) { // The stream is either malicious or poorly implemented and returned a number of // bytes larger than the buffer supplied to it. throw new InvalidDataException(SR.GenericInvalidData); } cancellationToken.ThrowIfCancellationRequested(); // Feed the data from base stream into decompression engine _inflater.SetInput(_buffer, 0, bytesRead); } // Finish inflating any bytes in the input buffer int inflatedBytes = 0, bytesReadIteration = -1; while (inflatedBytes < buffer.Length && bytesReadIteration != 0) { bytesReadIteration = _inflater.Inflate(buffer.Span.Slice(inflatedBytes)); inflatedBytes += bytesReadIteration; } // There are a few different potential states here // 1. DeflateStream or GZipStream that succesfully read bytes => return those bytes // 2. DeflateStream or GZipStream that didn't read bytes and isn't finished => feed more input // 3. DeflateStream that didn't read bytes, but is finished => return 0 // 4. GZipStream that is finished but is appended with another gzip stream => feed more input // 5. GZipStream that is finished and appended with garbage => return 0 if (inflatedBytes != 0) { // If decompression output buffer is not empty, return immediately. return(inflatedBytes); } else if (_inflater.Finished() && (!_inflater.IsGzipStream() || !_inflater.NeedsInput())) { return(0); } else if (_inflater.NeedsInput()) { // We could have read in head information and didn't get any data. // Read from the base stream again. readTask = _stream.ReadAsync(_buffer, cancellationToken); } } } finally { AsyncOperationCompleting(); } }
public override async ValueTask <int> ReadAsync(Memory <byte> destination, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (_connection == null || destination.Length == 0) { // Response body fully consumed or the caller didn't ask for any data return(0); } Debug.Assert(_contentBytesRemaining > 0); if ((ulong)destination.Length > _contentBytesRemaining) { destination = destination.Slice(0, (int)_contentBytesRemaining); } ValueTask <int> readTask = _connection.ReadAsync(destination); int bytesRead; if (readTask.IsCompletedSuccessfully) { bytesRead = readTask.Result; } else { CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken); try { bytesRead = await readTask.ConfigureAwait(false); } catch (Exception exc) when(ShouldWrapInOperationCanceledException(exc, cancellationToken)) { throw CreateOperationCanceledException(exc, cancellationToken); } finally { ctr.Dispose(); } } if (bytesRead <= 0) { // A cancellation request may have caused the EOF. cancellationToken.ThrowIfCancellationRequested(); // Unexpected end of response stream. throw new IOException(SR.net_http_invalid_response); } Debug.Assert((ulong)bytesRead <= _contentBytesRemaining); _contentBytesRemaining -= (ulong)bytesRead; if (_contentBytesRemaining == 0) { // End of response body _connection.ReturnConnectionToPool(); _connection = null; } return(bytesRead); }
public static async Task <object?> Cast(ValueTask <T> source) => await source.ConfigureAwait(false);
public async Task CreateFromValue_Await() { ValueTask<int> t = new ValueTask<int>(42); Assert.Equal(42, await t); Assert.Equal(42, await t.ConfigureAwait(false)); Assert.Equal(42, await t.ConfigureAwait(true)); }
/// <summary> /// <see cref="System.Runtime.CompilerServices.ConfiguredTaskAwaitable{TResult}.ConfiguredTaskAwaiter"/>を取得します。 /// </summary> /// <returns><see cref="System.Runtime.CompilerServices.ConfiguredTaskAwaitable{TResult}.ConfiguredTaskAwaiter"/>を返します。</returns> public ConfiguredValueTaskAwaitable <TResult> .ConfiguredValueTaskAwaiter GetAwaiter() { return(_task.ConfigureAwait(_continue_on_captured_context).GetAwaiter()); }
public static ConfiguredValueTaskAwaitable Ignore(this ValueTask task) => task.ConfigureAwait(false);
public static TResult Run <TResult>(this ValueTask <TResult> task, bool continueOnCaputedContext = true) => task.ConfigureAwait(continueOnCaputedContext).GetAwaiter().GetResult();
static async Task IgnoreExceptionsAsync(ValueTask <int> task) { try { await task.ConfigureAwait(false); } catch { } }
public static void Run(this ValueTask task, bool continueOnCapturedContext = true) => task.ConfigureAwait(continueOnCapturedContext).GetAwaiter().GetResult();
private async ValueTask CompleteConnectAsync(ValueTask task) { await task.ConfigureAwait(false); _active = true; }
public static void RunAsync <TResult>(this ValueTask <TResult> task, bool continueOnCapturedContext = false) => _ = Task.Run(async() => await task.ConfigureAwait(continueOnCapturedContext));
static async ValueTask <TcpClient> WaitAndWrap(ValueTask <Socket> task) => new TcpClient(await task.ConfigureAwait(false));
public static ConfiguredValueTaskAwaitable <T> CAF <T>(this ValueTask <T> awaitable) => awaitable.ConfigureAwait(false);
static async ValueTask <Packet> AddContinuation(ValueTask <ArraySegment <byte> > headerBytes, BufferedByteReader bufferedByteReader, IByteHandler byteHandler, Func <int> getNextSequenceNumber, ProtocolErrorBehavior protocolErrorBehavior, IOBehavior ioBehavior) => await ReadPacketAfterHeader(await headerBytes.ConfigureAwait(false), bufferedByteReader, byteHandler, getNextSequenceNumber, protocolErrorBehavior, ioBehavior).ConfigureAwait(false);
public static ConfiguredValueTaskAwaitable CAF(this ValueTask awaitable) => awaitable.ConfigureAwait(false);
public static ConfiguredValueTaskAwaitable DonotCapture(this ValueTask task) { return(task.ConfigureAwait(false)); }
public WithCancellationValueTaskAwaitable(ValueTask <T> task, CancellationToken cancellationToken) { _awaitable = task.ConfigureAwait(false); _cancellationToken = cancellationToken; }
/// <summary> /// Make a task execute synchronously /// </summary> /// <param name="task">Task</param> /// <returns>Result</returns> public static T Sync <T>(this ValueTask <T> task) { return(task.ConfigureAwait(false).GetAwaiter().GetResult()); }
static async ValueTask <IMemoryOwner <byte> > AwaitAndReturnAsync(ValueTask <int> runningTask, byte[] localBuffer, int contentLength) { await runningTask.ConfigureAwait(false); return(new SqsResponseMemoryOwner(localBuffer, contentLength)); }
public static ConfiguredValueTaskAwaitable NoSync(this ValueTask task) { return(task.ConfigureAwait(false)); }
static async Task <TiffRational[]> TransformValueTaskAsync(ValueTask <TiffValueCollection <TiffRational> > valueTask) { TiffValueCollection <TiffRational> result = await valueTask.ConfigureAwait(false); return(result.GetOrCreateArray()); }
public async Task CreateFromTask_Await_ConfigureAwaitTrue() { Task<int> source = Task.Delay(1).ContinueWith(_ => 42); ValueTask<int> t = new ValueTask<int>(source); Assert.Equal(42, await t.ConfigureAwait(true)); }
public void ConfiguredAwaiter_OnCompleted(bool continueOnCapturedContext) { // Since ValueTask implements both OnCompleted and UnsafeOnCompleted, // OnCompleted typically won't be used by await, so we add an explicit test // for it here. ValueTask<int> t = new ValueTask<int>(42); var mres = new ManualResetEventSlim(); t.ConfigureAwait(continueOnCapturedContext).GetAwaiter().OnCompleted(() => mres.Set()); Assert.True(mres.Wait(10000)); }