diff --git a/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems b/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
index b864121125b8..fafe4b929222 100644
--- a/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
+++ b/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
@@ -551,6 +551,7 @@
+
diff --git a/src/mscorlib/shared/System/IO/FileStream.Unix.cs b/src/mscorlib/shared/System/IO/FileStream.Unix.cs
index 31b9ac53b486..d9fcf6571192 100644
--- a/src/mscorlib/shared/System/IO/FileStream.Unix.cs
+++ b/src/mscorlib/shared/System/IO/FileStream.Unix.cs
@@ -635,12 +635,12 @@ private unsafe void WriteNative(ReadOnlySpan source)
/// The buffer to write data from.
/// The token to monitor for cancellation requests.
/// A task that represents the asynchronous write operation.
- private Task WriteAsyncInternal(ReadOnlyMemory source, CancellationToken cancellationToken)
+ private ValueTask WriteAsyncInternal(ReadOnlyMemory source, CancellationToken cancellationToken)
{
Debug.Assert(_useAsyncIO);
if (cancellationToken.IsCancellationRequested)
- return Task.FromCanceled(cancellationToken);
+ return new ValueTask(Task.FromCanceled(cancellationToken));
if (_fileHandle.IsClosed)
throw Error.GetFileNotOpen();
@@ -667,11 +667,11 @@ private Task WriteAsyncInternal(ReadOnlyMemory source, CancellationToken c
source.Span.CopyTo(new Span(GetBuffer(), _writePos, source.Length));
_writePos += source.Length;
- return Task.CompletedTask;
+ return default;
}
catch (Exception exc)
{
- return Task.FromException(exc);
+ return new ValueTask(Task.FromException(exc));
}
finally
{
@@ -682,7 +682,7 @@ private Task WriteAsyncInternal(ReadOnlyMemory source, CancellationToken c
// Otherwise, issue the whole request asynchronously.
_asyncState.ReadOnlyMemory = source;
- return waitTask.ContinueWith((t, s) =>
+ return new ValueTask(waitTask.ContinueWith((t, s) =>
{
// The options available on Unix for writing asynchronously to an arbitrary file
// handle typically amount to just using another thread to do the synchronous write,
@@ -702,7 +702,7 @@ private Task WriteAsyncInternal(ReadOnlyMemory source, CancellationToken c
thisRef.WriteSpan(readOnlyMemory.Span);
}
finally { thisRef._asyncState.Release(); }
- }, this, CancellationToken.None, TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default);
+ }, this, CancellationToken.None, TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default));
}
/// Sets the current position of this stream to the given value.
diff --git a/src/mscorlib/shared/System/IO/FileStream.Windows.cs b/src/mscorlib/shared/System/IO/FileStream.Windows.cs
index 85f045426dbd..291a30bb5385 100644
--- a/src/mscorlib/shared/System/IO/FileStream.Windows.cs
+++ b/src/mscorlib/shared/System/IO/FileStream.Windows.cs
@@ -961,7 +961,7 @@ unsafe private Task ReadNativeAsync(Memory destination, int numBuffer
return completionSource.Task;
}
- private Task WriteAsyncInternal(ReadOnlyMemory source, CancellationToken cancellationToken)
+ private ValueTask WriteAsyncInternal(ReadOnlyMemory source, CancellationToken cancellationToken)
{
Debug.Assert(_useAsyncIO);
Debug.Assert((_readPos == 0 && _readLength == 0 && _writePos >= 0) || (_writePos == 0 && _readPos <= _readLength), "We're either reading or writing, but not both.");
@@ -1005,7 +1005,7 @@ private Task WriteAsyncInternal(ReadOnlyMemory source, CancellationToken c
// completely, we want to do the asynchronous flush/write as part of this operation
// rather than waiting until the next write that fills the buffer.
if (source.Length != remainingBuffer)
- return Task.CompletedTask;
+ return default;
Debug.Assert(_writePos == _bufferLength);
}
@@ -1051,7 +1051,7 @@ private Task WriteAsyncInternal(ReadOnlyMemory source, CancellationToken c
flushTask.IsFaulted ||
flushTask.IsCanceled)
{
- return flushTask;
+ return new ValueTask(flushTask);
}
}
@@ -1061,10 +1061,10 @@ private Task WriteAsyncInternal(ReadOnlyMemory source, CancellationToken c
// Finally, issue the write asynchronously, and return a Task that logically
// represents the write operation, including any flushing done.
Task writeTask = WriteAsyncInternalCore(source, cancellationToken);
- return
+ return new ValueTask(
(flushTask == null || flushTask.Status == TaskStatus.RanToCompletion) ? writeTask :
(writeTask.Status == TaskStatus.RanToCompletion) ? flushTask :
- Task.WhenAll(flushTask, writeTask);
+ Task.WhenAll(flushTask, writeTask));
}
private unsafe Task WriteAsyncInternalCore(ReadOnlyMemory source, CancellationToken cancellationToken)
@@ -1319,7 +1319,7 @@ private async Task AsyncModeCopyToAsync(Stream destination, int bufferSize, Canc
int bufferedBytes = _readLength - _readPos;
if (bufferedBytes > 0)
{
- await destination.WriteAsync(GetBuffer(), _readPos, bufferedBytes, cancellationToken).ConfigureAwait(false);
+ await destination.WriteAsync(new ReadOnlyMemory(GetBuffer(), _readPos, bufferedBytes), cancellationToken).ConfigureAwait(false);
_readPos = _readLength = 0;
}
}
@@ -1345,7 +1345,6 @@ private async Task AsyncModeCopyToAsync(Stream destination, int bufferSize, Canc
// Further, typically the CopyToAsync buffer size will be larger than that used by the FileStream, such that
// we'd likely be unable to use it anyway. Instead, we rent the buffer from a pool.
byte[] copyBuffer = ArrayPool.Shared.Rent(bufferSize);
- bufferSize = 0; // repurpose bufferSize to be the high water mark for the buffer, to avoid an extra field in the state machine
// Allocate an Overlapped we can use repeatedly for all operations
var awaitableOverlapped = new PreAllocatedOverlapped(AsyncCopyToAwaitable.s_callback, readAwaitable, copyBuffer);
@@ -1452,13 +1451,6 @@ private async Task AsyncModeCopyToAsync(Stream destination, int bufferSize, Canc
{
readAwaitable._position += numBytesRead;
}
-
- // (and keep track of the maximum number of bytes in the buffer we used, to avoid excessive and unnecessary
- // clearing of the buffer before we return it to the pool)
- if (numBytesRead > bufferSize)
- {
- bufferSize = numBytesRead;
- }
}
finally
{
@@ -1479,7 +1471,7 @@ private async Task AsyncModeCopyToAsync(Stream destination, int bufferSize, Canc
}
// Write out the read data.
- await destination.WriteAsync(copyBuffer, 0, (int)readAwaitable._numBytes, cancellationToken).ConfigureAwait(false);
+ await destination.WriteAsync(new ReadOnlyMemory(copyBuffer, 0, (int)readAwaitable._numBytes), cancellationToken).ConfigureAwait(false);
}
}
finally
@@ -1488,8 +1480,7 @@ private async Task AsyncModeCopyToAsync(Stream destination, int bufferSize, Canc
cancellationReg.Dispose();
awaitableOverlapped.Dispose();
- Array.Clear(copyBuffer, 0, bufferSize);
- ArrayPool.Shared.Return(copyBuffer, clearArray: false);
+ ArrayPool.Shared.Return(copyBuffer);
// Make sure the stream's current position reflects where we ended up
if (!_fileHandle.IsClosed && CanSeek)
diff --git a/src/mscorlib/shared/System/IO/FileStream.cs b/src/mscorlib/shared/System/IO/FileStream.cs
index 4593768bd96f..717b73ff1339 100644
--- a/src/mscorlib/shared/System/IO/FileStream.cs
+++ b/src/mscorlib/shared/System/IO/FileStream.cs
@@ -458,10 +458,10 @@ public override Task WriteAsync(byte[] buffer, int offset, int count, Cancellati
if (IsClosed)
throw Error.GetFileNotOpen();
- return WriteAsyncInternal(new ReadOnlyMemory(buffer, offset, count), cancellationToken);
+ return WriteAsyncInternal(new ReadOnlyMemory(buffer, offset, count), cancellationToken).AsTask();
}
- public override Task WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default(CancellationToken))
{
if (!_useAsyncIO || GetType() != typeof(FileStream))
{
@@ -473,7 +473,7 @@ public override Task WriteAsync(byte[] buffer, int offset, int count, Cancellati
if (cancellationToken.IsCancellationRequested)
{
- return Task.FromCanceled(cancellationToken);
+ return new ValueTask(Task.FromCanceled(cancellationToken));
}
if (IsClosed)
@@ -853,7 +853,7 @@ public override IAsyncResult BeginWrite(byte[] array, int offset, int numBytes,
if (!IsAsync)
return base.BeginWrite(array, offset, numBytes, callback, state);
else
- return TaskToApm.Begin(WriteAsyncInternal(new ReadOnlyMemory(array, offset, numBytes), CancellationToken.None), callback, state);
+ return TaskToApm.Begin(WriteAsyncInternal(new ReadOnlyMemory(array, offset, numBytes), CancellationToken.None).AsTask(), callback, state);
}
public override int EndRead(IAsyncResult asyncResult)
diff --git a/src/mscorlib/shared/System/IO/MemoryStream.cs b/src/mscorlib/shared/System/IO/MemoryStream.cs
index c5e5ea918b44..8e573b749baf 100644
--- a/src/mscorlib/shared/System/IO/MemoryStream.cs
+++ b/src/mscorlib/shared/System/IO/MemoryStream.cs
@@ -752,11 +752,11 @@ public override Task WriteAsync(Byte[] buffer, int offset, int count, Cancellati
}
}
- public override Task WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default(CancellationToken))
{
if (cancellationToken.IsCancellationRequested)
{
- return Task.FromCanceled(cancellationToken);
+ return new ValueTask(Task.FromCanceled(cancellationToken));
}
try
@@ -771,15 +771,15 @@ public override Task WriteAsync(Byte[] buffer, int offset, int count, Cancellati
{
Write(source.Span);
}
- return Task.CompletedTask;
+ return default;
}
catch (OperationCanceledException oce)
{
- return Task.FromCancellation(oce);
+ return new ValueTask(Task.FromCancellation(oce));
}
catch (Exception exception)
{
- return Task.FromException(exception);
+ return new ValueTask(Task.FromException(exception));
}
}
diff --git a/src/mscorlib/shared/System/IO/StreamReader.cs b/src/mscorlib/shared/System/IO/StreamReader.cs
index 4e724ddb3004..22ec6e645bb6 100644
--- a/src/mscorlib/shared/System/IO/StreamReader.cs
+++ b/src/mscorlib/shared/System/IO/StreamReader.cs
@@ -1091,7 +1091,7 @@ internal override async ValueTask ReadAsyncInternal(Memory buffer, Ca
{
Debug.Assert(_bytePos <= _encoding.Preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?");
int tmpBytePos = _bytePos;
- int len = await tmpStream.ReadAsync(tmpByteBuffer, tmpBytePos, tmpByteBuffer.Length - tmpBytePos, cancellationToken).ConfigureAwait(false);
+ int len = await tmpStream.ReadAsync(new Memory(tmpByteBuffer, tmpBytePos, tmpByteBuffer.Length - tmpBytePos), cancellationToken).ConfigureAwait(false);
Debug.Assert(len >= 0, "Stream.Read returned a negative number! This is a bug in your stream class.");
if (len == 0)
@@ -1127,7 +1127,7 @@ internal override async ValueTask ReadAsyncInternal(Memory buffer, Ca
{
Debug.Assert(_bytePos == 0, "_bytePos can be non zero only when we are trying to _checkPreamble. Are two threads using this StreamReader at the same time?");
- _byteLen = await tmpStream.ReadAsync(tmpByteBuffer, 0, tmpByteBuffer.Length, cancellationToken).ConfigureAwait(false);
+ _byteLen = await tmpStream.ReadAsync(new Memory(tmpByteBuffer), cancellationToken).ConfigureAwait(false);
Debug.Assert(_byteLen >= 0, "Stream.Read returned a negative number! This is a bug in your stream class.");
@@ -1303,7 +1303,7 @@ private async Task ReadBufferAsync()
{
Debug.Assert(_bytePos <= _encoding.Preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?");
int tmpBytePos = _bytePos;
- int len = await tmpStream.ReadAsync(tmpByteBuffer, tmpBytePos, tmpByteBuffer.Length - tmpBytePos).ConfigureAwait(false);
+ int len = await tmpStream.ReadAsync(new Memory(tmpByteBuffer, tmpBytePos, tmpByteBuffer.Length - tmpBytePos)).ConfigureAwait(false);
Debug.Assert(len >= 0, "Stream.Read returned a negative number! This is a bug in your stream class.");
if (len == 0)
@@ -1325,7 +1325,7 @@ private async Task ReadBufferAsync()
else
{
Debug.Assert(_bytePos == 0, "_bytePos can be non zero only when we are trying to _checkPreamble. Are two threads using this StreamReader at the same time?");
- _byteLen = await tmpStream.ReadAsync(tmpByteBuffer, 0, tmpByteBuffer.Length).ConfigureAwait(false);
+ _byteLen = await tmpStream.ReadAsync(new Memory(tmpByteBuffer)).ConfigureAwait(false);
Debug.Assert(_byteLen >= 0, "Stream.Read returned a negative number! Bug in stream class.");
if (_byteLen == 0) // We're at EOF
diff --git a/src/mscorlib/shared/System/IO/StreamWriter.cs b/src/mscorlib/shared/System/IO/StreamWriter.cs
index 6cdcd695244c..a37624428066 100644
--- a/src/mscorlib/shared/System/IO/StreamWriter.cs
+++ b/src/mscorlib/shared/System/IO/StreamWriter.cs
@@ -963,14 +963,14 @@ private static async Task FlushAsyncInternal(StreamWriter _this, bool flushStrea
byte[] preamble = encoding.GetPreamble();
if (preamble.Length > 0)
{
- await stream.WriteAsync(preamble, 0, preamble.Length, cancellationToken).ConfigureAwait(false);
+ await stream.WriteAsync(new ReadOnlyMemory(preamble), cancellationToken).ConfigureAwait(false);
}
}
int count = encoder.GetBytes(charBuffer, 0, charPos, byteBuffer, 0, flushEncoder);
if (count > 0)
{
- await stream.WriteAsync(byteBuffer, 0, count, cancellationToken).ConfigureAwait(false);
+ await stream.WriteAsync(new ReadOnlyMemory(byteBuffer, 0, count), cancellationToken).ConfigureAwait(false);
}
// By definition, calling Flush should flush the stream, but this is
diff --git a/src/mscorlib/shared/System/IO/UnmanagedMemoryStream.cs b/src/mscorlib/shared/System/IO/UnmanagedMemoryStream.cs
index 171113542f11..2f0f34afeea1 100644
--- a/src/mscorlib/shared/System/IO/UnmanagedMemoryStream.cs
+++ b/src/mscorlib/shared/System/IO/UnmanagedMemoryStream.cs
@@ -783,11 +783,11 @@ public override Task WriteAsync(Byte[] buffer, Int32 offset, Int32 count, Cancel
///
/// Buffer that will be written.
/// Token that can be used to cancel the operation.
- public override Task WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default(CancellationToken))
{
if (cancellationToken.IsCancellationRequested)
{
- return Task.FromCanceled(cancellationToken);
+ return new ValueTask(Task.FromCanceled(cancellationToken));
}
try
@@ -802,11 +802,11 @@ public override Task WriteAsync(Byte[] buffer, Int32 offset, Int32 count, Cancel
{
Write(source.Span);
}
- return Task.CompletedTask;
+ return default;
}
catch (Exception ex)
{
- return Task.FromException(ex);
+ return new ValueTask(Task.FromException(ex));
}
}
diff --git a/src/mscorlib/shared/System/IO/UnmanagedMemoryStreamWrapper.cs b/src/mscorlib/shared/System/IO/UnmanagedMemoryStreamWrapper.cs
index 90bb21ac5b28..f34c3c413791 100644
--- a/src/mscorlib/shared/System/IO/UnmanagedMemoryStreamWrapper.cs
+++ b/src/mscorlib/shared/System/IO/UnmanagedMemoryStreamWrapper.cs
@@ -217,7 +217,7 @@ public override Task WriteAsync(Byte[] buffer, Int32 offset, Int32 count, Cancel
return _unmanagedStream.WriteAsync(buffer, offset, count, cancellationToken);
}
- public override Task WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default(CancellationToken))
{
return _unmanagedStream.WriteAsync(source, cancellationToken);
}
diff --git a/src/mscorlib/shared/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs b/src/mscorlib/shared/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs
index 49cdaccb0e4b..0e1220d11900 100644
--- a/src/mscorlib/shared/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs
+++ b/src/mscorlib/shared/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs
@@ -8,6 +8,108 @@
namespace System.Runtime.CompilerServices
{
+ /// Represents a builder for asynchronous methods that return a .
+ [StructLayout(LayoutKind.Auto)]
+ public struct AsyncValueTaskMethodBuilder
+ {
+ /// The to which most operations are delegated.
+ private AsyncTaskMethodBuilder _methodBuilder; // mutable struct; do not make it readonly
+ /// true if completed synchronously and successfully; otherwise, false.
+ private bool _haveResult;
+ /// true if the builder should be used for setting/getting the result; otherwise, false.
+ private bool _useBuilder;
+
+ /// Creates an instance of the struct.
+ /// The initialized instance.
+ public static AsyncValueTaskMethodBuilder Create() =>
+#if CORERT
+ // corert's AsyncTaskMethodBuilder.Create() currently does additional debugger-related
+ // work, so we need to delegate to it.
+ new AsyncValueTaskMethodBuilder() { _methodBuilder = AsyncTaskMethodBuilder.Create() };
+#else
+ // _methodBuilder should be initialized to AsyncTaskMethodBuilder.Create(), but on coreclr
+ // that Create() is a nop, so we can just return the default here.
+ default;
+#endif
+
+ /// Begins running the builder with the associated state machine.
+ /// The type of the state machine.
+ /// The state machine instance, passed by reference.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine =>
+ // will provide the right ExecutionContext semantics
+#if netstandard
+ _methodBuilder.Start(ref stateMachine);
+#else
+ AsyncMethodBuilderCore.Start(ref stateMachine);
+#endif
+
+ /// Associates the builder with the specified state machine.
+ /// The state machine instance to associate with the builder.
+ public void SetStateMachine(IAsyncStateMachine stateMachine) => _methodBuilder.SetStateMachine(stateMachine);
+
+ /// Marks the task as successfully completed.
+ public void SetResult()
+ {
+ if (_useBuilder)
+ {
+ _methodBuilder.SetResult();
+ }
+ else
+ {
+ _haveResult = true;
+ }
+ }
+
+ /// Marks the task as failed and binds the specified exception to the task.
+ /// The exception to bind to the task.
+ public void SetException(Exception exception) => _methodBuilder.SetException(exception);
+
+ /// Gets the task for this builder.
+ public ValueTask Task
+ {
+ get
+ {
+ if (_haveResult)
+ {
+ return default;
+ }
+ else
+ {
+ _useBuilder = true;
+ return new ValueTask(_methodBuilder.Task);
+ }
+ }
+ }
+
+ /// Schedules the state machine to proceed to the next action when the specified awaiter completes.
+ /// The type of the awaiter.
+ /// The type of the state machine.
+ /// The awaiter.
+ /// The state machine.
+ public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine)
+ where TAwaiter : INotifyCompletion
+ where TStateMachine : IAsyncStateMachine
+ {
+ _useBuilder = true;
+ _methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine);
+ }
+
+ /// Schedules the state machine to proceed to the next action when the specified awaiter completes.
+ /// The type of the awaiter.
+ /// The type of the state machine.
+ /// The awaiter.
+ /// The state machine.
+ [SecuritySafeCritical]
+ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine)
+ where TAwaiter : ICriticalNotifyCompletion
+ where TStateMachine : IAsyncStateMachine
+ {
+ _useBuilder = true;
+ _methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
+ }
+ }
+
/// Represents a builder for asynchronous methods that returns a .
/// The type of the result.
[StructLayout(LayoutKind.Auto)]
@@ -32,7 +134,7 @@ public static AsyncValueTaskMethodBuilder Create() =>
#else
// _methodBuilder should be initialized to AsyncTaskMethodBuilder.Create(), but on coreclr
// that Create() is a nop, so we can just return the default here.
- default(AsyncValueTaskMethodBuilder);
+ default;
#endif
/// Begins running the builder with the associated state machine.
diff --git a/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs b/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs
index f22b9d94bf65..65d3d5670d86 100644
--- a/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs
+++ b/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs
@@ -5,9 +5,115 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
+using System.Threading.Tasks.Sources;
+
+#if !netstandard
+using Internal.Runtime.CompilerServices;
+#endif
namespace System.Runtime.CompilerServices
{
+ /// Provides an awaitable type that enables configured awaits on a .
+ [StructLayout(LayoutKind.Auto)]
+ public readonly struct ConfiguredValueTaskAwaitable
+ {
+ /// The wrapped .
+ private readonly ValueTask _value;
+
+ /// Initializes the awaitable.
+ /// The wrapped .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal ConfiguredValueTaskAwaitable(ValueTask value) => _value = value;
+
+ /// Returns an awaiter for this instance.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ConfiguredValueTaskAwaiter GetAwaiter() => new ConfiguredValueTaskAwaiter(_value);
+
+ /// Provides an awaiter for a .
+ [StructLayout(LayoutKind.Auto)]
+ public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion
+#if CORECLR
+ , IValueTaskAwaiter
+#endif
+ {
+ /// The value being awaited.
+ private readonly ValueTask _value;
+
+ /// Initializes the awaiter.
+ /// The value to be awaited.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal ConfiguredValueTaskAwaiter(ValueTask value) => _value = value;
+
+ /// Gets whether the has completed.
+ public bool IsCompleted
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _value.IsCompleted;
+ }
+
+ /// Gets the result of the ValueTask.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [StackTraceHidden]
+ public void GetResult() => _value.ThrowIfCompletedUnsuccessfully();
+
+ /// Schedules the continuation action for the .
+ public void OnCompleted(Action continuation)
+ {
+ if (_value.ObjectIsTask)
+ {
+ _value.UnsafeTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
+ }
+ else if (_value._obj != null)
+ {
+ _value.UnsafeValueTaskSource.OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token,
+ ValueTaskSourceOnCompletedFlags.FlowExecutionContext |
+ (_value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None));
+ }
+ else
+ {
+ Task.CompletedTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
+ }
+ }
+
+ /// Schedules the continuation action for the .
+ public void UnsafeOnCompleted(Action continuation)
+ {
+ if (_value.ObjectIsTask)
+ {
+ _value.UnsafeTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ else if (_value._obj != null)
+ {
+ _value.UnsafeValueTaskSource.OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token,
+ _value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None);
+ }
+ else
+ {
+ Task.CompletedTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ }
+
+#if CORECLR
+ void IValueTaskAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box)
+ {
+ if (_value.ObjectIsTask)
+ {
+ TaskAwaiter.UnsafeOnCompletedInternal(_value.UnsafeTask, box, _value.ContinueOnCapturedContext);
+ }
+ else if (_value._obj != null)
+ {
+ _value.UnsafeValueTaskSource.OnCompleted(ValueTaskAwaiter.s_invokeAsyncStateMachineBox, box, _value._token,
+ _value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None);
+ }
+ else
+ {
+ TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, _value.ContinueOnCapturedContext);
+ }
+ }
+#endif
+ }
+ }
+
/// Provides an awaitable type that enables configured awaits on a .
/// The type of the result produced.
[StructLayout(LayoutKind.Auto)]
@@ -15,78 +121,98 @@ public readonly struct ConfiguredValueTaskAwaitable
{
/// The wrapped .
private readonly ValueTask _value;
- /// true to attempt to marshal the continuation back to the original context captured; otherwise, false.
- private readonly bool _continueOnCapturedContext;
/// Initializes the awaitable.
/// The wrapped .
- ///
- /// true to attempt to marshal the continuation back to the original synchronization context captured; otherwise, false.
- ///
- internal ConfiguredValueTaskAwaitable(ValueTask value, bool continueOnCapturedContext)
- {
- _value = value;
- _continueOnCapturedContext = continueOnCapturedContext;
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal ConfiguredValueTaskAwaitable(ValueTask value) => _value = value;
/// Returns an awaiter for this instance.
- public ConfiguredValueTaskAwaiter GetAwaiter() =>
- new ConfiguredValueTaskAwaiter(_value, _continueOnCapturedContext);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ConfiguredValueTaskAwaiter GetAwaiter() => new ConfiguredValueTaskAwaiter(_value);
/// Provides an awaiter for a .
[StructLayout(LayoutKind.Auto)]
- public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion, IConfiguredValueTaskAwaiter
+ public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion
+#if CORECLR
+ , IValueTaskAwaiter
+#endif
{
/// The value being awaited.
private readonly ValueTask _value;
- /// The value to pass to ConfigureAwait.
- internal readonly bool _continueOnCapturedContext;
/// Initializes the awaiter.
/// The value to be awaited.
- /// The value to pass to ConfigureAwait.
- internal ConfiguredValueTaskAwaiter(ValueTask value, bool continueOnCapturedContext)
- {
- _value = value;
- _continueOnCapturedContext = continueOnCapturedContext;
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal ConfiguredValueTaskAwaiter(ValueTask value) => _value = value;
/// Gets whether the has completed.
- public bool IsCompleted => _value.IsCompleted;
+ public bool IsCompleted
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _value.IsCompleted;
+ }
/// Gets the result of the ValueTask.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
[StackTraceHidden]
- public TResult GetResult() =>
- _value._task == null ?
- _value._result :
- _value._task.GetAwaiter().GetResult();
+ public TResult GetResult() => _value.Result;
/// Schedules the continuation action for the .
- public void OnCompleted(Action continuation) =>
- _value.AsTask().ConfigureAwait(_continueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
+ public void OnCompleted(Action continuation)
+ {
+ if (_value.ObjectIsTask)
+ {
+ _value.UnsafeTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
+ }
+ else if (_value._obj != null)
+ {
+ _value.UnsafeValueTaskSource.OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token,
+ ValueTaskSourceOnCompletedFlags.FlowExecutionContext |
+ (_value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None));
+ }
+ else
+ {
+ Task.CompletedTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
+ }
+ }
/// Schedules the continuation action for the .
- public void UnsafeOnCompleted(Action continuation) =>
- _value.AsTask().ConfigureAwait(_continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
-
- /// Gets the task underlying .
- internal Task AsTask() => _value.AsTask();
+ public void UnsafeOnCompleted(Action continuation)
+ {
+ if (_value.ObjectIsTask)
+ {
+ _value.UnsafeTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ else if (_value._obj != null)
+ {
+ _value.UnsafeValueTaskSource.OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token,
+ _value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None);
+ }
+ else
+ {
+ Task.CompletedTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ }
- /// Gets the task underlying the incomplete .
- /// This method is used when awaiting and IsCompleted returned false; thus we expect the value task to be wrapping a non-null task.
- Task IConfiguredValueTaskAwaiter.GetTask(out bool continueOnCapturedContext)
+#if CORECLR
+ void IValueTaskAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box)
{
- continueOnCapturedContext = _continueOnCapturedContext;
- return _value.AsTaskExpectNonNull();
+ if (_value.ObjectIsTask)
+ {
+ TaskAwaiter.UnsafeOnCompletedInternal(_value.UnsafeTask, box, _value.ContinueOnCapturedContext);
+ }
+ else if (_value._obj != null)
+ {
+ _value.UnsafeValueTaskSource.OnCompleted(ValueTaskAwaiter.s_invokeAsyncStateMachineBox, box, _value._token,
+ _value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None);
+ }
+ else
+ {
+ TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, _value.ContinueOnCapturedContext);
+ }
}
+#endif
}
}
-
- ///
- /// Internal interface used to enable extract the Task from arbitrary configured ValueTask awaiters.
- ///
- internal interface IConfiguredValueTaskAwaiter
- {
- Task GetTask(out bool continueOnCapturedContext);
- }
}
diff --git a/src/mscorlib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs b/src/mscorlib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs
index 3f212d8bf9b8..0414a05a0dfb 100644
--- a/src/mscorlib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs
+++ b/src/mscorlib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs
@@ -4,50 +4,198 @@
using System.Diagnostics;
using System.Threading.Tasks;
+using System.Threading.Tasks.Sources;
namespace System.Runtime.CompilerServices
{
+ /// Provides an awaiter for a .
+ public readonly struct ValueTaskAwaiter : ICriticalNotifyCompletion
+#if CORECLR
+ , IValueTaskAwaiter
+#endif
+ {
+ /// Shim used to invoke an passed as the state argument to a .
+ internal static readonly Action