Imported Upstream version 5.16.0.100

Former-commit-id: 38faa55fb9669e35e7d8448b15c25dc447f25767
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-08-07 15:19:03 +00:00
parent 0a9828183b
commit 7d7f676260
4419 changed files with 170950 additions and 90273 deletions

View File

@@ -7,6 +7,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Tasks.Exte
{DE90AD0B-649D-4062-B8D9-9658DE140532} = {DE90AD0B-649D-4062-B8D9-9658DE140532}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Tasks.Extensions.Performance.Tests", "tests\Performance\System.Threading.Tasks.Extensions.Performance.Tests.csproj", "{77E38A48-61ED-4D79-9136-D88617EE3558}"
ProjectSection(ProjectDependencies) = postProject
{DE90AD0B-649D-4062-B8D9-9658DE140532} = {DE90AD0B-649D-4062-B8D9-9658DE140532}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Tasks.Extensions", "src\System.Threading.Tasks.Extensions.csproj", "{DE90AD0B-649D-4062-B8D9-9658DE140532}"
ProjectSection(ProjectDependencies) = postProject
{0DF7FA9A-E7D3-4CEF-862B-A37F5BBBB54C} = {0DF7FA9A-E7D3-4CEF-862B-A37F5BBBB54C}
@@ -30,6 +35,10 @@ Global
{275B161B-D525-48A0-B1DE-344273AB9A99}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{275B161B-D525-48A0-B1DE-344273AB9A99}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
{275B161B-D525-48A0-B1DE-344273AB9A99}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
{77E38A48-61ED-4D79-9136-D88617EE3558}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
{77E38A48-61ED-4D79-9136-D88617EE3558}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{77E38A48-61ED-4D79-9136-D88617EE3558}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
{77E38A48-61ED-4D79-9136-D88617EE3558}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
{DE90AD0B-649D-4062-B8D9-9658DE140532}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
{DE90AD0B-649D-4062-B8D9-9658DE140532}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
{DE90AD0B-649D-4062-B8D9-9658DE140532}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
@@ -44,6 +53,7 @@ Global
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{275B161B-D525-48A0-B1DE-344273AB9A99} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
{77E38A48-61ED-4D79-9136-D88617EE3558} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
{DE90AD0B-649D-4062-B8D9-9658DE140532} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
{0DF7FA9A-E7D3-4CEF-862B-A37F5BBBB54C} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
EndGlobalSection

View File

@@ -2,7 +2,10 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\dir.props" />
<PropertyGroup>
<AssemblyVersion>4.1.2.0</AssemblyVersion>
<AssemblyVersion>4.2.0.0</AssemblyVersion>
<!-- System.Threading.Tasks.Extensions has forwarded types into the runtime on netcoreapp/uap
It must win over assemblies versioned at 4.2.* -->
<AssemblyVersion Condition="'$(TargetGroup)' == 'netcoreapp' OR '$(TargetGroup)' == 'uap' ">4.3.0.0</AssemblyVersion>
<AssemblyKey>Open</AssemblyKey>
<IsNETCoreApp>true</IsNETCoreApp>
<IsUAP>true</IsUAP>

View File

@@ -11,7 +11,7 @@
</ProjectReference>
<ProjectReference Include="..\src\System.Threading.Tasks.Extensions.csproj" />
<InboxOnTargetFramework Include="netcoreapp2.0" />
<InboxOnTargetFramework Include="netcoreapp2.1" />
<InboxOnTargetFramework Include="$(UAPvNextTFM)" />
<!-- this package is part of the implementation closure of NETStandard.Library
@@ -19,4 +19,4 @@
<SuppressMetaPackage Include="NETStandard.Library" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
</Project>

View File

@@ -13,6 +13,18 @@ namespace System.Runtime.CompilerServices
public AsyncMethodBuilderAttribute(System.Type builderType) { }
public System.Type BuilderType { get { throw null; } }
}
public partial struct AsyncValueTaskMethodBuilder
{
private object _dummy;
public System.Threading.Tasks.ValueTask Task { get { throw null; } }
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : System.Runtime.CompilerServices.INotifyCompletion where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine { }
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine { }
public static System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder Create() { throw null; }
public void SetException(System.Exception exception) { }
public void SetResult() { }
public void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine stateMachine) { }
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine { }
}
public partial struct AsyncValueTaskMethodBuilder<TResult>
{
private TResult _result;
@@ -25,22 +37,43 @@ namespace System.Runtime.CompilerServices
public void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine stateMachine) { }
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine { }
}
public readonly partial struct ConfiguredValueTaskAwaitable
{
private readonly object _dummy;
public System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable.ConfiguredValueTaskAwaiter GetAwaiter() { throw null; }
public readonly partial struct ConfiguredValueTaskAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion
{
private readonly object _dummy;
public bool IsCompleted { get { throw null; } }
public void GetResult() { }
public void OnCompleted(System.Action continuation) { }
public void UnsafeOnCompleted(System.Action continuation) { }
}
}
public readonly partial struct ConfiguredValueTaskAwaitable<TResult>
{
private readonly object _dummy;
public System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable<TResult>.ConfiguredValueTaskAwaiter GetAwaiter() { throw null; }
public partial struct ConfiguredValueTaskAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion
public readonly partial struct ConfiguredValueTaskAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion
{
private object _dummy;
private readonly object _dummy;
public bool IsCompleted { get { throw null; } }
public TResult GetResult() { throw null; }
public void OnCompleted(System.Action continuation) { }
public void UnsafeOnCompleted(System.Action continuation) { }
}
}
public partial struct ValueTaskAwaiter<TResult> : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion
public readonly partial struct ValueTaskAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion
{
private object _dummy;
private readonly object _dummy;
public bool IsCompleted { get { throw null; } }
public void GetResult() { }
public void OnCompleted(System.Action continuation) { }
public void UnsafeOnCompleted(System.Action continuation) { }
}
public readonly partial struct ValueTaskAwaiter<TResult> : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion
{
private readonly object _dummy;
public bool IsCompleted { get { throw null; } }
public TResult GetResult() { throw null; }
public void OnCompleted(System.Action continuation) { }
@@ -49,11 +82,32 @@ namespace System.Runtime.CompilerServices
}
namespace System.Threading.Tasks
{
[System.Runtime.CompilerServices.AsyncMethodBuilderAttribute(typeof(System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder))]
public readonly partial struct ValueTask : System.IEquatable<System.Threading.Tasks.ValueTask>
{
internal readonly object _dummy;
public ValueTask(System.Threading.Tasks.Task task) { throw null; }
public ValueTask(System.Threading.Tasks.Sources.IValueTaskSource source, short token) { throw null; }
public bool IsCanceled { get { throw null; } }
public bool IsCompleted { get { throw null; } }
public bool IsCompletedSuccessfully { get { throw null; } }
public bool IsFaulted { get { throw null; } }
public System.Threading.Tasks.Task AsTask() { throw null; }
public System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) { throw null; }
public override bool Equals(object obj) { throw null; }
public bool Equals(System.Threading.Tasks.ValueTask other) { throw null; }
public System.Runtime.CompilerServices.ValueTaskAwaiter GetAwaiter() { throw null; }
public override int GetHashCode() { throw null; }
public System.Threading.Tasks.ValueTask Preserve() { throw null; }
public static bool operator ==(System.Threading.Tasks.ValueTask left, System.Threading.Tasks.ValueTask right) { throw null; }
public static bool operator !=(System.Threading.Tasks.ValueTask left, System.Threading.Tasks.ValueTask right) { throw null; }
}
[System.Runtime.CompilerServices.AsyncMethodBuilderAttribute(typeof(System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder<>))]
public readonly partial struct ValueTask<TResult> : System.IEquatable<System.Threading.Tasks.ValueTask<TResult>>
{
internal readonly TResult _result;
public ValueTask(System.Threading.Tasks.Task<TResult> task) { throw null; }
public ValueTask(System.Threading.Tasks.Sources.IValueTaskSource<TResult> source, short token) { throw null; }
public ValueTask(TResult result) { throw null; }
public bool IsCanceled { get { throw null; } }
public bool IsCompleted { get { throw null; } }
@@ -62,14 +116,42 @@ namespace System.Threading.Tasks
public TResult Result { get { throw null; } }
public System.Threading.Tasks.Task<TResult> AsTask() { throw null; }
public System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable<TResult> ConfigureAwait(bool continueOnCapturedContext) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
public static System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder<TResult> CreateAsyncMethodBuilder() { throw null; }
public override bool Equals(object obj) { throw null; }
public bool Equals(System.Threading.Tasks.ValueTask<TResult> other) { throw null; }
public System.Runtime.CompilerServices.ValueTaskAwaiter<TResult> GetAwaiter() { throw null; }
public override int GetHashCode() { throw null; }
public System.Threading.Tasks.ValueTask<TResult> Preserve() { throw null; }
public static bool operator ==(System.Threading.Tasks.ValueTask<TResult> left, System.Threading.Tasks.ValueTask<TResult> right) { throw null; }
public static bool operator !=(System.Threading.Tasks.ValueTask<TResult> left, System.Threading.Tasks.ValueTask<TResult> right) { throw null; }
public override string ToString() { throw null; }
}
}
namespace System.Threading.Tasks.Sources
{
[System.Flags]
public enum ValueTaskSourceOnCompletedFlags
{
None,
UseSchedulingContext = 0x1,
FlowExecutionContext = 0x2,
}
public enum ValueTaskSourceStatus
{
Pending = 0,
Succeeded = 1,
Faulted = 2,
Canceled = 3
}
public interface IValueTaskSource
{
System.Threading.Tasks.Sources.ValueTaskSourceStatus GetStatus(short token);
void OnCompleted(System.Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags);
void GetResult(short token);
}
public interface IValueTaskSource<out TResult>
{
System.Threading.Tasks.Sources.ValueTaskSourceStatus GetStatus(short token);
void OnCompleted(System.Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags);
TResult GetResult(short token);
}
}

View File

@@ -4,12 +4,6 @@
<PropertyGroup>
<ProjectGuid>{0DF7FA9A-E7D3-4CEF-862B-A37F5BBBB54C}</ProjectGuid>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netcoreapp' Or '$(TargetGroup)' == 'uap'">true</IsPartialFacadeAssembly>
<!--
Netstandard assembly version is frozen and thus cannot adde any more APIs to it because
the types have been moved inbox and type-forwarded into CoreLib. The only way to add more
APIs is to add them directly to the particular platform.
-->
<AssemblyVersion Condition="$(TargetGroup.StartsWith('netstandard'))">4.1.1.0</AssemblyVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />

View File

@@ -6,8 +6,8 @@
<DocumentationFile>$(OutputPath)$(MSBuildProjectName).xml</DocumentationFile>
<PackageTargetFramework Condition="'$(TargetGroup)' == 'netstandard1.0'">netstandard1.0;portable-net45+win8+wp8+wpa81</PackageTargetFramework>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' != 'netstandard' and '$(TargetGroup)' != 'netstandard1.0'">true</IsPartialFacadeAssembly>
<DefineConstants Condition="'$(IsPartialFacadeAssembly)' != 'true'">$(DefineConstants);netstandard</DefineConstants>
<ExcludeResourcesImport Condition="'$(IsPartialFacadeAssembly)'=='true'">true</ExcludeResourcesImport>
<AssemblyVersion Condition="$(TargetGroup.StartsWith('netstandard'))">4.1.1.0</AssemblyVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
@@ -23,15 +23,34 @@
<ReferenceFromRuntime Include="System.Private.CoreLib" />
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true'">
<Compile Include="System\Runtime\CompilerServices\AsyncMethodBuilderAttribute.cs" />
<Compile Include="System\Runtime\CompilerServices\AsyncValueTaskMethodBuilder.cs" />
<Compile Include="System\Runtime\CompilerServices\ConfiguredValueTaskAwaitable.cs" />
<Compile Include="System\Runtime\CompilerServices\ValueTaskAwaiter.cs" />
<Compile Include="System\Threading\Tasks\ValueTask.cs" />
<Compile Include="System\ThrowHelper.cs" />
<Compile Include="$(CommonPath)\CoreLib\System\Diagnostics\StackTraceHiddenAttribute.cs">
<Link>Common\CoreLib\System\Diagnostics\StackTraceHiddenAttribute.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\CoreLib\System\Runtime\CompilerServices\AsyncMethodBuilderAttribute.cs">
<Link>Common\CoreLib\System\Runtime\CompilerServices\AsyncMethodBuilderAttribute.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\CoreLib\System\Runtime\CompilerServices\AsyncValueTaskMethodBuilder.cs">
<Link>Common\CoreLib\System\Runtime\CompilerServices\AsyncValueTaskMethodBuilder.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\CoreLib\System\Runtime\CompilerServices\ConfiguredValueTaskAwaitable.cs">
<Link>Common\CoreLib\System\Runtime\CompilerServices\ConfiguredValueTaskAwaitable.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\CoreLib\System\Runtime\CompilerServices\ValueTaskAwaiter.cs">
<Link>Common\CoreLib\System\Runtime\CompilerServices\ValueTaskAwaiter.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\CoreLib\System\Threading\Tasks\ValueTask.cs">
<Link>Common\CoreLib\System\Threading\Tasks\ValueTask.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\CoreLib\System\Threading\Tasks\Sources\IValueTaskSource.cs">
<Link>Common\CoreLib\System\Threading\Tasks\Sources\IValueTaskSource.cs</Link>
</Compile>
<Reference Include="System.Collections" />
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.CompilerServices.Unsafe" />
<Reference Include="System.Threading.Tasks" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
</Project>

View File

@@ -1,21 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace System.Runtime.CompilerServices
{
/// <summary>
/// Indicates the type of the async method builder that should be used by a language compiler to
/// build the attributed type when used as the return type of an async method.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Delegate | AttributeTargets.Enum, Inherited = false, AllowMultiple = false)]
public sealed class AsyncMethodBuilderAttribute : Attribute
{
/// <summary>Initializes the <see cref="AsyncMethodBuilderAttribute"/>.</summary>
/// <param name="builderType">The <see cref="Type"/> of the associated builder.</param>
public AsyncMethodBuilderAttribute(Type builderType) => BuilderType = builderType;
/// <summary>Gets the <see cref="Type"/> of the associated builder.</summary>
public Type BuilderType { get; }
}
}

View File

@@ -1,102 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.InteropServices;
using System.Security;
using System.Threading.Tasks;
namespace System.Runtime.CompilerServices
{
/// <summary>Represents a builder for asynchronous methods that returns a <see cref="ValueTask{TResult}"/>.</summary>
/// <typeparam name="TResult">The type of the result.</typeparam>
[StructLayout(LayoutKind.Auto)]
public struct AsyncValueTaskMethodBuilder<TResult>
{
/// <summary>The <see cref="AsyncTaskMethodBuilder{TResult}"/> to which most operations are delegated.</summary>
private AsyncTaskMethodBuilder<TResult> _methodBuilder;
/// <summary>The result for this builder, if it's completed before any awaits occur.</summary>
private TResult _result;
/// <summary>true if <see cref="_result"/> contains the synchronous result for the async method; otherwise, false.</summary>
private bool _haveResult;
/// <summary>true if the builder should be used for setting/getting the result; otherwise, false.</summary>
private bool _useBuilder;
/// <summary>Creates an instance of the <see cref="AsyncValueTaskMethodBuilder{TResult}"/> struct.</summary>
/// <returns>The initialized instance.</returns>
public static AsyncValueTaskMethodBuilder<TResult> Create() =>
new AsyncValueTaskMethodBuilder<TResult>() { _methodBuilder = AsyncTaskMethodBuilder<TResult>.Create() };
/// <summary>Begins running the builder with the associated state machine.</summary>
/// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
/// <param name="stateMachine">The state machine instance, passed by reference.</param>
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine =>
_methodBuilder.Start(ref stateMachine); // will provide the right ExecutionContext semantics
/// <summary>Associates the builder with the specified state machine.</summary>
/// <param name="stateMachine">The state machine instance to associate with the builder.</param>
public void SetStateMachine(IAsyncStateMachine stateMachine) => _methodBuilder.SetStateMachine(stateMachine);
/// <summary>Marks the task as successfully completed.</summary>
/// <param name="result">The result to use to complete the task.</param>
public void SetResult(TResult result)
{
if (_useBuilder)
{
_methodBuilder.SetResult(result);
}
else
{
_result = result;
_haveResult = true;
}
}
/// <summary>Marks the task as failed and binds the specified exception to the task.</summary>
/// <param name="exception">The exception to bind to the task.</param>
public void SetException(Exception exception) => _methodBuilder.SetException(exception);
/// <summary>Gets the task for this builder.</summary>
public ValueTask<TResult> Task
{
get
{
if (_haveResult)
{
return new ValueTask<TResult>(_result);
}
else
{
_useBuilder = true;
return new ValueTask<TResult>(_methodBuilder.Task);
}
}
}
/// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary>
/// <typeparam name="TAwaiter">The type of the awaiter.</typeparam>
/// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
/// <param name="awaiter">the awaiter</param>
/// <param name="stateMachine">The state machine.</param>
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
{
_useBuilder = true;
_methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine);
}
/// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary>
/// <typeparam name="TAwaiter">The type of the awaiter.</typeparam>
/// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
/// <param name="awaiter">the awaiter</param>
/// <param name="stateMachine">The state machine.</param>
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine
{
_useBuilder = true;
_methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
}
}
}

View File

@@ -1,71 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace System.Runtime.CompilerServices
{
/// <summary>Provides an awaitable type that enables configured awaits on a <see cref="ValueTask{TResult}"/>.</summary>
/// <typeparam name="TResult">The type of the result produced.</typeparam>
[StructLayout(LayoutKind.Auto)]
public readonly struct ConfiguredValueTaskAwaitable<TResult>
{
/// <summary>The wrapped <see cref="ValueTask{TResult}"/>.</summary>
private readonly ValueTask<TResult> _value;
/// <summary>true to attempt to marshal the continuation back to the original context captured; otherwise, false.</summary>
private readonly bool _continueOnCapturedContext;
/// <summary>Initializes the awaitable.</summary>
/// <param name="value">The wrapped <see cref="ValueTask{TResult}"/>.</param>
/// <param name="continueOnCapturedContext">
/// true to attempt to marshal the continuation back to the original synchronization context captured; otherwise, false.
/// </param>
internal ConfiguredValueTaskAwaitable(ValueTask<TResult> value, bool continueOnCapturedContext)
{
_value = value;
_continueOnCapturedContext = continueOnCapturedContext;
}
/// <summary>Returns an awaiter for this <see cref="ConfiguredValueTaskAwaitable{TResult}"/> instance.</summary>
public ConfiguredValueTaskAwaiter GetAwaiter() =>
new ConfiguredValueTaskAwaiter(_value, _continueOnCapturedContext);
/// <summary>Provides an awaiter for a <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary>
[StructLayout(LayoutKind.Auto)]
public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion
{
/// <summary>The value being awaited.</summary>
private readonly ValueTask<TResult> _value;
/// <summary>The value to pass to ConfigureAwait.</summary>
private readonly bool _continueOnCapturedContext;
/// <summary>Initializes the awaiter.</summary>
/// <param name="value">The value to be awaited.</param>
/// <param name="continueOnCapturedContext">The value to pass to ConfigureAwait.</param>
internal ConfiguredValueTaskAwaiter(ValueTask<TResult> value, bool continueOnCapturedContext)
{
_value = value;
_continueOnCapturedContext = continueOnCapturedContext;
}
/// <summary>Gets whether the <see cref="ConfiguredValueTaskAwaitable{TResult}"/> has completed.</summary>
public bool IsCompleted => _value.IsCompleted;
/// <summary>Gets the result of the ValueTask.</summary>
public TResult GetResult() =>
_value._task == null ?
_value._result :
_value._task.GetAwaiter().GetResult();
/// <summary>Schedules the continuation action for the <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary>
public void OnCompleted(Action continuation) =>
_value.AsTask().ConfigureAwait(_continueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
/// <summary>Schedules the continuation action for the <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary>
public void UnsafeOnCompleted(Action continuation) =>
_value.AsTask().ConfigureAwait(_continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
}
}
}

View File

@@ -1,37 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace System.Runtime.CompilerServices
{
/// <summary>Provides an awaiter for a <see cref="ValueTask{TResult}"/>.</summary>
public readonly struct ValueTaskAwaiter<TResult> : ICriticalNotifyCompletion
{
/// <summary>The value being awaited.</summary>
private readonly ValueTask<TResult> _value;
/// <summary>Initializes the awaiter.</summary>
/// <param name="value">The value to be awaited.</param>
internal ValueTaskAwaiter(ValueTask<TResult> value) => _value = value;
/// <summary>Gets whether the <see cref="ValueTask{TResult}"/> has completed.</summary>
public bool IsCompleted => _value.IsCompleted;
/// <summary>Gets the result of the ValueTask.</summary>
public TResult GetResult() =>
_value._task == null ?
_value._result :
_value._task.GetAwaiter().GetResult();
/// <summary>Schedules the continuation action for this ValueTask.</summary>
public void OnCompleted(Action continuation) =>
_value.AsTask().ConfigureAwait(continueOnCapturedContext: true).GetAwaiter().OnCompleted(continuation);
/// <summary>Schedules the continuation action for this ValueTask.</summary>
public void UnsafeOnCompleted(Action continuation) =>
_value.AsTask().ConfigureAwait(continueOnCapturedContext: true).GetAwaiter().UnsafeOnCompleted(continuation);
}
}

View File

@@ -1,167 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
#if !MONO
using System.ComponentModel;
#endif
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace System.Threading.Tasks
{
/// <summary>
/// Provides a value type that wraps a <see cref="Task{TResult}"/> and a <typeparamref name="TResult"/>,
/// only one of which is used.
/// </summary>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <remarks>
/// <para>
/// Methods may return an instance of this value type when it's likely that the result of their
/// operations will be available synchronously and when the method is expected to be invoked so
/// frequently that the cost of allocating a new <see cref="Task{TResult}"/> for each call will
/// be prohibitive.
/// </para>
/// <para>
/// There are tradeoffs to using a <see cref="ValueTask{TResult}"/> instead of a <see cref="Task{TResult}"/>.
/// For example, while a <see cref="ValueTask{TResult}"/> can help avoid an allocation in the case where the
/// successful result is available synchronously, it also contains two fields whereas a <see cref="Task{TResult}"/>
/// as a reference type is a single field. This means that a method call ends up returning two fields worth of
/// data instead of one, which is more data to copy. It also means that if a method that returns one of these
/// is awaited within an async method, the state machine for that async method will be larger due to needing
/// to store the struct that's two fields instead of a single reference.
/// </para>
/// <para>
/// Further, for uses other than consuming the result of an asynchronous operation via await,
/// <see cref="ValueTask{TResult}"/> can lead to a more convoluted programming model, which can in turn actually
/// lead to more allocations. For example, consider a method that could return either a <see cref="Task{TResult}"/>
/// with a cached task as a common result or a <see cref="ValueTask{TResult}"/>. If the consumer of the result
/// wants to use it as a <see cref="Task{TResult}"/>, such as to use with in methods like Task.WhenAll and Task.WhenAny,
/// the <see cref="ValueTask{TResult}"/> would first need to be converted into a <see cref="Task{TResult}"/> using
/// <see cref="ValueTask{TResult}.AsTask"/>, which leads to an allocation that would have been avoided if a cached
/// <see cref="Task{TResult}"/> had been used in the first place.
/// </para>
/// <para>
/// As such, the default choice for any asynchronous method should be to return a <see cref="Task"/> or
/// <see cref="Task{TResult}"/>. Only if performance analysis proves it worthwhile should a <see cref="ValueTask{TResult}"/>
/// be used instead of <see cref="Task{TResult}"/>. There is no non-generic version of <see cref="ValueTask{TResult}"/>
/// as the Task.CompletedTask property may be used to hand back a successfully completed singleton in the case where
/// a <see cref="Task"/>-returning method completes synchronously and successfully.
/// </para>
/// </remarks>
[AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder<>))]
[StructLayout(LayoutKind.Auto)]
public readonly struct ValueTask<TResult> : IEquatable<ValueTask<TResult>>
{
/// <summary>The task to be used if the operation completed asynchronously or if it completed synchronously but non-successfully.</summary>
internal readonly Task<TResult> _task;
/// <summary>The result to be used if the operation completed successfully synchronously.</summary>
internal readonly TResult _result;
/// <summary>Initialize the <see cref="ValueTask{TResult}"/> with the result of the successful operation.</summary>
/// <param name="result">The result.</param>
public ValueTask(TResult result)
{
_task = null;
_result = result;
}
/// <summary>
/// Initialize the <see cref="ValueTask{TResult}"/> with a <see cref="Task{TResult}"/> that represents the operation.
/// </summary>
/// <param name="task">The task.</param>
public ValueTask(Task<TResult> task)
{
_task = task ?? throw new ArgumentNullException(nameof(task));
_result = default(TResult);
}
/// <summary>Returns the hash code for this instance.</summary>
public override int GetHashCode() =>
_task != null ? _task.GetHashCode() :
_result != null ? _result.GetHashCode() :
0;
/// <summary>Returns a value indicating whether this value is equal to a specified <see cref="object"/>.</summary>
public override bool Equals(object obj) =>
obj is ValueTask<TResult> &&
Equals((ValueTask<TResult>)obj);
/// <summary>Returns a value indicating whether this value is equal to a specified <see cref="ValueTask{TResult}"/> value.</summary>
public bool Equals(ValueTask<TResult> other) =>
_task != null || other._task != null ?
_task == other._task :
EqualityComparer<TResult>.Default.Equals(_result, other._result);
/// <summary>Returns a value indicating whether two <see cref="ValueTask{TResult}"/> values are equal.</summary>
public static bool operator==(ValueTask<TResult> left, ValueTask<TResult> right) =>
left.Equals(right);
/// <summary>Returns a value indicating whether two <see cref="ValueTask{TResult}"/> values are not equal.</summary>
public static bool operator!=(ValueTask<TResult> left, ValueTask<TResult> right) =>
!left.Equals(right);
/// <summary>
/// Gets a <see cref="Task{TResult}"/> object to represent this ValueTask. It will
/// either return the wrapped task object if one exists, or it'll manufacture a new
/// task object to represent the result.
/// </summary>
public Task<TResult> AsTask() =>
// Return the task if we were constructed from one, otherwise manufacture one. We don't
// cache the generated task into _task as it would end up changing both equality comparison
// and the hash code we generate in GetHashCode.
_task ?? Task.FromResult(_result);
/// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a completed operation.</summary>
public bool IsCompleted => _task == null || _task.IsCompleted;
/// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a successfully completed operation.</summary>
public bool IsCompletedSuccessfully => _task == null || _task.Status == TaskStatus.RanToCompletion;
/// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a failed operation.</summary>
public bool IsFaulted => _task != null && _task.IsFaulted;
/// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a canceled operation.</summary>
public bool IsCanceled => _task != null && _task.IsCanceled;
/// <summary>Gets the result.</summary>
public TResult Result => _task == null ? _result : _task.GetAwaiter().GetResult();
/// <summary>Gets an awaiter for this value.</summary>
public ValueTaskAwaiter<TResult> GetAwaiter() => new ValueTaskAwaiter<TResult>(this);
/// <summary>Configures an awaiter for this value.</summary>
/// <param name="continueOnCapturedContext">
/// true to attempt to marshal the continuation back to the captured context; otherwise, false.
/// </param>
public ConfiguredValueTaskAwaitable<TResult> ConfigureAwait(bool continueOnCapturedContext) =>
new ConfiguredValueTaskAwaitable<TResult>(this, continueOnCapturedContext: continueOnCapturedContext);
/// <summary>Gets a string-representation of this <see cref="ValueTask{TResult}"/>.</summary>
public override string ToString()
{
if (_task != null)
{
return _task.Status == TaskStatus.RanToCompletion && _task.Result != null ?
_task.Result.ToString() :
string.Empty;
}
else
{
return _result != null ?
_result.ToString() :
string.Empty;
}
}
// TODO: Remove CreateAsyncMethodBuilder once the C# compiler relies on the AsyncBuilder attribute.
/// <summary>Creates a method builder for use with an async method.</summary>
/// <returns>The created builder.</returns>
#if !MONO
[EditorBrowsable(EditorBrowsableState.Never)] // intended only for compiler consumption
#endif
public static AsyncValueTaskMethodBuilder<TResult> CreateAsyncMethodBuilder() => AsyncValueTaskMethodBuilder<TResult>.Create();
}
}

View File

@@ -0,0 +1,40 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace System
{
internal static class ThrowHelper
{
internal static void ThrowArgumentNullException(ExceptionArgument argument) =>
throw GetArgumentNullException(argument);
internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument) =>
throw GetArgumentOutOfRangeException(argument);
private static ArgumentNullException GetArgumentNullException(ExceptionArgument argument) =>
new ArgumentNullException(GetArgumentName(argument));
private static ArgumentOutOfRangeException GetArgumentOutOfRangeException(ExceptionArgument argument) =>
new ArgumentOutOfRangeException(GetArgumentName(argument));
[MethodImpl(MethodImplOptions.NoInlining)]
private static string GetArgumentName(ExceptionArgument argument)
{
Debug.Assert(Enum.IsDefined(typeof(ExceptionArgument), argument),
$"The enum value is not defined, please check the {nameof(ExceptionArgument)} enum.");
return argument.ToString();
}
}
internal enum ExceptionArgument
{
task,
source,
state
}
}

View File

@@ -11,6 +11,7 @@ namespace System.Runtime.CompilerServices.Tests
[Theory]
[InlineData(typeof(string))]
[InlineData(typeof(int))]
[InlineData(typeof(AsyncValueTaskMethodBuilder))]
[InlineData(typeof(AsyncValueTaskMethodBuilder<>))]
[InlineData(typeof(AsyncValueTaskMethodBuilder<int>))]
[InlineData(typeof(AsyncValueTaskMethodBuilder<string>))]

View File

@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.CompilerServices;
using Xunit;
@@ -11,16 +10,32 @@ namespace System.Threading.Tasks.Tests
public class AsyncValueTaskMethodBuilderTests
{
[Fact]
public void Create_ReturnsDefaultInstance()
public void NonGeneric_Create_ReturnsDefaultInstance()
{
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
Assert.Equal(default(AsyncValueTaskMethodBuilder<int>), b); // implementation detail being verified
AsyncValueTaskMethodBuilder b = default;
Assert.Equal(default, b); // implementation detail being verified
}
[Fact]
public void SetResult_BeforeAccessTask_ValueTaskContainsValue()
public void Generic_Create_ReturnsDefaultInstance()
{
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
AsyncValueTaskMethodBuilder<int> b = default;
Assert.Equal(default, b); // implementation detail being verified
}
[Fact]
public void NonGeneric_SetResult_BeforeAccessTask_ValueTaskIsDefault()
{
AsyncValueTaskMethodBuilder b = default;
b.SetResult();
ValueTask vt = b.Task;
Assert.True(vt == default);
}
[Fact]
public void Generic_SetResult_BeforeAccessTask_ValueTaskContainsValue()
{
AsyncValueTaskMethodBuilder<int> b = default;
b.SetResult(42);
ValueTask<int> vt = b.Task;
Assert.True(vt.IsCompletedSuccessfully);
@@ -29,9 +44,20 @@ namespace System.Threading.Tasks.Tests
}
[Fact]
public void SetResult_AfterAccessTask_ValueTaskContainsValue()
public void NonGeneric_SetResult_AfterAccessTask_ValueTaskContainsValue()
{
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
AsyncValueTaskMethodBuilder b = default;
ValueTask vt = b.Task;
b.SetResult();
Assert.False(vt == default);
Assert.True(vt.IsCompletedSuccessfully);
Assert.True(WrapsTask(vt));
}
[Fact]
public void Generic_SetResult_AfterAccessTask_ValueTaskContainsValue()
{
AsyncValueTaskMethodBuilder<int> b = default;
ValueTask<int> vt = b.Task;
b.SetResult(42);
Assert.True(vt.IsCompletedSuccessfully);
@@ -40,9 +66,20 @@ namespace System.Threading.Tasks.Tests
}
[Fact]
public void SetException_BeforeAccessTask_FaultsTask()
public void NonGeneric_SetException_BeforeAccessTask_FaultsTask()
{
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
AsyncValueTaskMethodBuilder b = default;
var e = new FormatException();
b.SetException(e);
ValueTask vt = b.Task;
Assert.True(vt.IsFaulted);
Assert.Same(e, Assert.Throws<FormatException>(() => vt.GetAwaiter().GetResult()));
}
[Fact]
public void Generic_SetException_BeforeAccessTask_FaultsTask()
{
AsyncValueTaskMethodBuilder<int> b = default;
var e = new FormatException();
b.SetException(e);
ValueTask<int> vt = b.Task;
@@ -51,9 +88,20 @@ namespace System.Threading.Tasks.Tests
}
[Fact]
public void SetException_AfterAccessTask_FaultsTask()
public void NonGeneric_SetException_AfterAccessTask_FaultsTask()
{
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
AsyncValueTaskMethodBuilder b = default;
var e = new FormatException();
ValueTask vt = b.Task;
b.SetException(e);
Assert.True(vt.IsFaulted);
Assert.Same(e, Assert.Throws<FormatException>(() => vt.GetAwaiter().GetResult()));
}
[Fact]
public void Generic_SetException_AfterAccessTask_FaultsTask()
{
AsyncValueTaskMethodBuilder<int> b = default;
var e = new FormatException();
ValueTask<int> vt = b.Task;
b.SetException(e);
@@ -62,9 +110,20 @@ namespace System.Threading.Tasks.Tests
}
[Fact]
public void SetException_OperationCanceledException_CancelsTask()
public void NonGeneric_SetException_OperationCanceledException_CancelsTask()
{
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
AsyncValueTaskMethodBuilder b = default;
var e = new OperationCanceledException();
ValueTask vt = b.Task;
b.SetException(e);
Assert.True(vt.IsCanceled);
Assert.Same(e, Assert.Throws<OperationCanceledException>(() => vt.GetAwaiter().GetResult()));
}
[Fact]
public void Generic_SetException_OperationCanceledException_CancelsTask()
{
AsyncValueTaskMethodBuilder<int> b = default;
var e = new OperationCanceledException();
ValueTask<int> vt = b.Task;
b.SetException(e);
@@ -73,9 +132,19 @@ namespace System.Threading.Tasks.Tests
}
[Fact]
public void Start_InvokesMoveNext()
public void NonGeneric_Start_InvokesMoveNext()
{
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
AsyncValueTaskMethodBuilder b = default;
int invokes = 0;
var dsm = new DelegateStateMachine { MoveNextDelegate = () => invokes++ };
b.Start(ref dsm);
Assert.Equal(1, invokes);
}
[Fact]
public void Generic_Start_InvokesMoveNext()
{
AsyncValueTaskMethodBuilder<int> b = default;
int invokes = 0;
var dsm = new DelegateStateMachine { MoveNextDelegate = () => invokes++ };
b.Start(ref dsm);
@@ -87,9 +156,40 @@ namespace System.Threading.Tasks.Tests
[InlineData(2, false)]
[InlineData(1, true)]
[InlineData(2, true)]
public void AwaitOnCompleted_ForcesTaskCreation(int numAwaits, bool awaitUnsafe)
public void NonGeneric_AwaitOnCompleted_ForcesTaskCreation(int numAwaits, bool awaitUnsafe)
{
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
AsyncValueTaskMethodBuilder b = default;
var dsm = new DelegateStateMachine();
TaskAwaiter<int> t = new TaskCompletionSource<int>().Task.GetAwaiter();
Assert.InRange(numAwaits, 1, int.MaxValue);
for (int i = 1; i <= numAwaits; i++)
{
if (awaitUnsafe)
{
b.AwaitUnsafeOnCompleted(ref t, ref dsm);
}
else
{
b.AwaitOnCompleted(ref t, ref dsm);
}
}
b.SetResult();
Assert.True(WrapsTask(b.Task));
Assert.True(b.Task.IsCompletedSuccessfully);
}
[Theory]
[InlineData(1, false)]
[InlineData(2, false)]
[InlineData(1, true)]
[InlineData(2, true)]
public void Generic_AwaitOnCompleted_ForcesTaskCreation(int numAwaits, bool awaitUnsafe)
{
AsyncValueTaskMethodBuilder<int> b = default;
var dsm = new DelegateStateMachine();
TaskAwaiter<int> t = new TaskCompletionSource<int>().Task.GetAwaiter();
@@ -115,14 +215,22 @@ namespace System.Threading.Tasks.Tests
[Fact]
[ActiveIssue("https://github.com/dotnet/corefx/issues/22506", TargetFrameworkMonikers.UapAot)]
public void SetStateMachine_InvalidArgument_ThrowsException()
public void NonGeneric_SetStateMachine_InvalidArgument_ThrowsException()
{
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
AsyncValueTaskMethodBuilder b = default;
AssertExtensions.Throws<ArgumentNullException>("stateMachine", () => b.SetStateMachine(null));
}
[Fact]
public void Start_ExecutionContextChangesInMoveNextDontFlowOut()
[ActiveIssue("https://github.com/dotnet/corefx/issues/22506", TargetFrameworkMonikers.UapAot)]
public void Generic_SetStateMachine_InvalidArgument_ThrowsException()
{
AsyncValueTaskMethodBuilder<int> b = default;
AssertExtensions.Throws<ArgumentNullException>("stateMachine", () => b.SetStateMachine(null));
}
[Fact]
public void NonGeneric_Start_ExecutionContextChangesInMoveNextDontFlowOut()
{
var al = new AsyncLocal<int> { Value = 0 };
int calls = 0;
@@ -144,7 +252,41 @@ namespace System.Threading.Tasks.Tests
Assert.Equal(2, al.Value);
Assert.Equal(2, calls);
AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
AsyncValueTaskMethodBuilder b = default;
b.Start(ref dsm);
Assert.Equal(2, al.Value); // change should not be visible
Assert.Equal(3, calls);
// Make sure we've not caused the Task to be allocated
b.SetResult();
ValueTask vt = b.Task;
Assert.False(WrapsTask(vt));
}
[Fact]
public void Generic_Start_ExecutionContextChangesInMoveNextDontFlowOut()
{
var al = new AsyncLocal<int> { Value = 0 };
int calls = 0;
var dsm = new DelegateStateMachine
{
MoveNextDelegate = () =>
{
al.Value++;
calls++;
}
};
dsm.MoveNext();
Assert.Equal(1, al.Value);
Assert.Equal(1, calls);
dsm.MoveNext();
Assert.Equal(2, al.Value);
Assert.Equal(2, calls);
AsyncValueTaskMethodBuilder<int> b = default;
b.Start(ref dsm);
Assert.Equal(2, al.Value); // change should not be visible
Assert.Equal(3, calls);
@@ -160,7 +302,25 @@ namespace System.Threading.Tasks.Tests
[InlineData(1)]
[InlineData(2)]
[InlineData(10)]
public static async Task UsedWithAsyncMethod_CompletesSuccessfully(int yields)
public static async Task NonGeneric_UsedWithAsyncMethod_CompletesSuccessfully(int yields)
{
await ValueTaskReturningAsyncMethod(42);
ValueTask vt = ValueTaskReturningAsyncMethod(84);
Assert.Equal(yields > 0, WrapsTask(vt));
async ValueTask ValueTaskReturningAsyncMethod(int result)
{
for (int i = 0; i < yields; i++) await Task.Yield();
}
}
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(2)]
[InlineData(10)]
public static async Task Generic_UsedWithAsyncMethod_CompletesSuccessfully(int yields)
{
Assert.Equal(42, await ValueTaskReturningAsyncMethod(42));
@@ -175,7 +335,129 @@ namespace System.Threading.Tasks.Tests
}
}
/// <summary>Gets whether the ValueTask has a non-null Task.</summary>
[Fact]
public static async Task AwaitTasksAndValueTasks_InTaskAndValueTaskMethods()
{
for (int i = 0; i < 2; i++)
{
await TaskReturningMethod();
Assert.Equal(17, await TaskInt32ReturningMethod());
await ValueTaskReturningMethod();
Assert.Equal(18, await ValueTaskInt32ReturningMethod());
}
async Task TaskReturningMethod()
{
for (int i = 0; i < 3; i++)
{
// Complete
await Task.CompletedTask;
await Task.FromResult(42);
await new ValueTask();
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(Task.FromException<int>(new FormatException())));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(ManualResetValueTaskSource.Completed(0, new FormatException()), 0));
Assert.Equal(42, await new ValueTask<int>(42));
Assert.Equal(42, await new ValueTask<int>(Task.FromResult(42)));
Assert.Equal(42, await new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(Task.FromException<int>(new FormatException())));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(ManualResetValueTaskSource.Completed(0, new FormatException()), 0));
// Incomplete
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(Task.Delay(1).ContinueWith(_ => throw new FormatException())));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(ManualResetValueTaskSource.Delay(1, 0, new FormatException()), 0));
Assert.Equal(42, await new ValueTask<int>(Task.Delay(1).ContinueWith(_ => 42)));
Assert.Equal(42, await new ValueTask<int>(ManualResetValueTaskSource.Delay(1, 42, null), 0));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(Task.Delay(1).ContinueWith<int>(_ => throw new FormatException())));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(ManualResetValueTaskSource.Delay(1, 0, new FormatException()), 0));
await Task.Yield();
}
}
async Task<int> TaskInt32ReturningMethod()
{
for (int i = 0; i < 3; i++)
{
// Complete
await Task.CompletedTask;
await Task.FromResult(42);
await new ValueTask();
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(Task.FromException<int>(new FormatException())));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(ManualResetValueTaskSource.Completed(0, new FormatException()), 0));
Assert.Equal(42, await new ValueTask<int>(42));
Assert.Equal(42, await new ValueTask<int>(Task.FromResult(42)));
Assert.Equal(42, await new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(Task.FromException<int>(new FormatException())));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(ManualResetValueTaskSource.Completed(0, new FormatException()), 0));
// Incomplete
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(Task.Delay(1).ContinueWith(_ => throw new FormatException())));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(ManualResetValueTaskSource.Delay(1, 0, new FormatException()), 0));
Assert.Equal(42, await new ValueTask<int>(Task.Delay(1).ContinueWith(_ => 42)));
Assert.Equal(42, await new ValueTask<int>(ManualResetValueTaskSource.Delay(1, 42, null), 0));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(Task.Delay(1).ContinueWith<int>(_ => throw new FormatException())));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(ManualResetValueTaskSource.Delay(1, 0, new FormatException()), 0));
await Task.Yield();
}
return 17;
}
async ValueTask ValueTaskReturningMethod()
{
for (int i = 0; i < 3; i++)
{
// Complete
await Task.CompletedTask;
await Task.FromResult(42);
await new ValueTask();
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(Task.FromException<int>(new FormatException())));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(ManualResetValueTaskSource.Completed(0, new FormatException()), 0));
Assert.Equal(42, await new ValueTask<int>(42));
Assert.Equal(42, await new ValueTask<int>(Task.FromResult(42)));
Assert.Equal(42, await new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(Task.FromException<int>(new FormatException())));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(ManualResetValueTaskSource.Completed(0, new FormatException()), 0));
// Incomplete
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(Task.Delay(1).ContinueWith(_ => throw new FormatException())));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(ManualResetValueTaskSource.Delay(1, 0, new FormatException()), 0));
Assert.Equal(42, await new ValueTask<int>(Task.Delay(1).ContinueWith(_ => 42)));
Assert.Equal(42, await new ValueTask<int>(ManualResetValueTaskSource.Delay(1, 42, null), 0));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(Task.Delay(1).ContinueWith<int>(_ => throw new FormatException())));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(ManualResetValueTaskSource.Delay(1, 0, new FormatException()), 0));
await Task.Yield();
}
}
async ValueTask<int> ValueTaskInt32ReturningMethod()
{
for (int i = 0; i < 3; i++)
{
// Complete
await Task.CompletedTask;
await Task.FromResult(42);
await new ValueTask();
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(Task.FromException<int>(new FormatException())));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(ManualResetValueTaskSource.Completed(0, new FormatException()), 0));
Assert.Equal(42, await new ValueTask<int>(42));
Assert.Equal(42, await new ValueTask<int>(Task.FromResult(42)));
Assert.Equal(42, await new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(Task.FromException<int>(new FormatException())));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(ManualResetValueTaskSource.Completed(0, new FormatException()), 0));
// Incomplete
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(Task.Delay(1).ContinueWith(_ => throw new FormatException())));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(ManualResetValueTaskSource.Delay(1, 0, new FormatException()), 0));
Assert.Equal(42, await new ValueTask<int>(Task.Delay(1).ContinueWith(_ => 42)));
Assert.Equal(42, await new ValueTask<int>(ManualResetValueTaskSource.Delay(1, 42, null), 0));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(Task.Delay(1).ContinueWith<int>(_ => throw new FormatException())));
await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(ManualResetValueTaskSource.Delay(1, 0, new FormatException()), 0));
await Task.Yield();
}
return 18;
}
}
private static bool WrapsTask(ValueTask vt) => vt != default;
private static bool WrapsTask<T>(ValueTask<T> vt) => ReferenceEquals(vt.AsTask(), vt.AsTask());
private struct DelegateStateMachine : IAsyncStateMachine

View File

@@ -4,6 +4,7 @@
<BuildConfigurations>
netcoreapp;
uap;
netfx;
</BuildConfigurations>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildConfigurations>
netcoreapp;
</BuildConfigurations>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,259 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.CompilerServices;
using System.Threading.Tasks.Sources;
using System.Threading.Tasks.Tests;
using Microsoft.Xunit.Performance;
using Xunit;
namespace System.Threading.Tasks
{
public class ValueTaskPerfTest
{
[Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
public async Task Await_FromResult()
{
ValueTask<int> vt = new ValueTask<int>(42);
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
long iters = Benchmark.InnerIterationCount;
using (iteration.StartMeasurement())
{
for (long i = 0; i < iters; i++)
{
await vt;
}
}
}
}
[Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
public async Task Await_FromCompletedTask()
{
ValueTask<int> vt = new ValueTask<int>(Task.FromResult(42));
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
long iters = Benchmark.InnerIterationCount;
using (iteration.StartMeasurement())
{
for (long i = 0; i < iters; i++)
{
await vt;
}
}
}
}
[Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
public async Task Await_FromCompletedValueTaskSource()
{
ValueTask<int> vt = new ValueTask<int>(ManualResetValueTaskSource.Completed<int>(42), 0);
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
long iters = Benchmark.InnerIterationCount;
using (iteration.StartMeasurement())
{
for (long i = 0; i < iters; i++)
{
await vt;
}
}
}
}
[Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
public async Task CreateAndAwait_FromResult()
{
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
long iters = Benchmark.InnerIterationCount;
using (iteration.StartMeasurement())
{
for (long i = 0; i < iters; i++)
{
await new ValueTask<int>((int)i);
}
}
}
}
[Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
public async Task CreateAndAwait_FromResult_ConfigureAwait()
{
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
long iters = Benchmark.InnerIterationCount;
using (iteration.StartMeasurement())
{
for (long i = 0; i < iters; i++)
{
await new ValueTask<int>((int)i).ConfigureAwait(false);
}
}
}
}
[Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
public async Task CreateAndAwait_FromCompletedTask()
{
Task<int> t = Task.FromResult(42);
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
long iters = Benchmark.InnerIterationCount;
using (iteration.StartMeasurement())
{
for (long i = 0; i < iters; i++)
{
await new ValueTask<int>(t);
}
}
}
}
[Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
public async Task CreateAndAwait_FromCompletedTask_ConfigureAwait()
{
Task<int> t = Task.FromResult(42);
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
long iters = Benchmark.InnerIterationCount;
using (iteration.StartMeasurement())
{
for (long i = 0; i < iters; i++)
{
await new ValueTask<int>(t).ConfigureAwait(false);
}
}
}
}
[Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
public async Task CreateAndAwait_FromCompletedValueTaskSource()
{
IValueTaskSource<int> vts = ManualResetValueTaskSource.Completed(42);
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
long iters = Benchmark.InnerIterationCount;
using (iteration.StartMeasurement())
{
for (long i = 0; i < iters; i++)
{
await new ValueTask<int>(vts, 0);
}
}
}
}
[Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
public async Task CreateAndAwait_FromCompletedValueTaskSource_ConfigureAwait()
{
IValueTaskSource<int> vts = ManualResetValueTaskSource.Completed(42);
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
long iters = Benchmark.InnerIterationCount;
using (iteration.StartMeasurement())
{
for (long i = 0; i < iters; i++)
{
await new ValueTask<int>(vts, 0).ConfigureAwait(false);
}
}
}
}
[Benchmark(InnerIterationCount = 1_000_000), MeasureGCAllocations]
public async Task CreateAndAwait_FromYieldingAsyncMethod()
{
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
long iters = Benchmark.InnerIterationCount;
using (iteration.StartMeasurement())
{
for (long i = 0; i < iters; i++)
{
await new ValueTask<int>(YieldOnce());
}
}
}
}
[Benchmark(InnerIterationCount = 1_000_000), MeasureGCAllocations]
public async Task CreateAndAwait_FromDelayedTCS()
{
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
long iters = Benchmark.InnerIterationCount;
using (iteration.StartMeasurement())
{
for (long i = 0; i < iters; i++)
{
var tcs = new TaskCompletionSource<int>();
ValueTask<int> vt = AwaitTcsAsValueTask(tcs);
tcs.SetResult(42);
await vt;
}
}
}
}
[Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
public void Copy_PassAsArgumentAndReturn_FromResult()
{
ValueTask<int> vt = new ValueTask<int>(42);
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
long iters = Benchmark.InnerIterationCount;
using (iteration.StartMeasurement())
{
for (long i = 0; i < iters; i++)
{
vt = ReturnValueTask(vt);
}
}
}
}
[Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
public void Copy_PassAsArgumentAndReturn_FromTask()
{
ValueTask<int> vt = new ValueTask<int>(Task.FromResult(42));
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
long iters = Benchmark.InnerIterationCount;
using (iteration.StartMeasurement())
{
for (long i = 0; i < iters; i++)
{
vt = ReturnValueTask(vt);
}
}
}
}
[Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
public void Copy_PassAsArgumentAndReturn_FromValueTaskSource()
{
ValueTask<int> vt = new ValueTask<int>(ManualResetValueTaskSource.Completed(42), 0);
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
long iters = Benchmark.InnerIterationCount;
using (iteration.StartMeasurement())
{
for (long i = 0; i < iters; i++)
{
vt = ReturnValueTask(vt);
}
}
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static ValueTask<int> ReturnValueTask(ValueTask<int> vt) => vt;
private async ValueTask<int> AwaitTcsAsValueTask(TaskCompletionSource<int> tcs) => await new ValueTask<int>(tcs.Task).ConfigureAwait(false);
private async Task<int> YieldOnce() { await Task.Yield(); return 42; }
}
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<IncludePerformanceTests>true</IncludePerformanceTests>
<ProjectGuid>{77E38A48-61ED-4D79-9136-D88617EE3558}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<!-- Default configurations to help VS understand the configurations -->
<ItemGroup>
<Compile Include="Perf.ValueTask.cs" />
<Compile Include="$(CommonTestPath)\System\PerfUtils.cs">
<Link>Common\System\PerfUtils.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)\System\Threading\Tasks\Sources\ManualResetValueTaskSource.cs">
<Link>Common\System\Threading\Tasks\Sources\ManualResetValueTaskSource.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(CommonPath)\..\perf\PerfRunner\PerfRunner.csproj">
<Project>{69e46a6f-9966-45a5-8945-2559fe337827}</Project>
<Name>PerfRunner</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>

View File

@@ -6,12 +6,20 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="AsyncMethodBuilderAttributeTests.cs" />
<Compile Include="AsyncValueTaskMethodBuilderTests.cs" />
<Compile Include="ValueTaskTests.cs" />
<Compile Include="$(CommonTestPath)\System\Threading\Tasks\Sources\ManualResetValueTaskSource.cs">
<Link>Common\System\Threading\Tasks\Sources\ManualResetValueTaskSource.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>