diff --git a/src/libraries/Common/src/System/Runtime/CompilerServices/RuntimeAsyncMethodGenerationAttribute.cs b/src/libraries/Common/src/System/Runtime/CompilerServices/RuntimeAsyncMethodGenerationAttribute.cs new file mode 100644 index 00000000000000..6152da7b384ed2 --- /dev/null +++ b/src/libraries/Common/src/System/Runtime/CompilerServices/RuntimeAsyncMethodGenerationAttribute.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Runtime.CompilerServices; + +[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] +internal sealed class RuntimeAsyncMethodGenerationAttribute(bool runtimeAsync) : Attribute +{ + public bool RuntimeAsync => runtimeAsync; +} diff --git a/src/libraries/Common/src/System/Threading/AsyncOverSyncWithIoCancellation.cs b/src/libraries/Common/src/System/Threading/AsyncOverSyncWithIoCancellation.cs index 4233fc4094cb14..d4a786d2449f68 100644 --- a/src/libraries/Common/src/System/Threading/AsyncOverSyncWithIoCancellation.cs +++ b/src/libraries/Common/src/System/Threading/AsyncOverSyncWithIoCancellation.cs @@ -82,6 +82,7 @@ private void Reset() /// performed by the function. /// [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder))] + [RuntimeAsyncMethodGeneration(false)] public static async ValueTask InvokeAsync(Action action, TState state, CancellationToken cancellationToken) { // Queue the work to complete asynchronously. Logically, this is just queueing a work item to the thread pool. @@ -120,6 +121,7 @@ public static async ValueTask InvokeAsync(Action action, TState /// performed by the function. /// [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))] + [RuntimeAsyncMethodGeneration(false)] public static async ValueTask InvokeAsync(Func func, TState state, CancellationToken cancellationToken) { // Queue the work to complete asynchronously. Logically, this is just queueing a work item to the thread pool. diff --git a/src/libraries/System.IO.Pipelines/src/System.IO.Pipelines.csproj b/src/libraries/System.IO.Pipelines/src/System.IO.Pipelines.csproj index 0153a1de4f8437..e0cb743c86e261 100644 --- a/src/libraries/System.IO.Pipelines/src/System.IO.Pipelines.csproj +++ b/src/libraries/System.IO.Pipelines/src/System.IO.Pipelines.csproj @@ -50,6 +50,8 @@ System.IO.Pipelines.PipeReader + diff --git a/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/StreamPipeReader.cs b/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/StreamPipeReader.cs index b3b96992666b63..9b8684f750afc5 100644 --- a/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/StreamPipeReader.cs +++ b/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/StreamPipeReader.cs @@ -237,6 +237,7 @@ private ValueTask ReadInternalAsync(int? minimumSize, CancellationTo #if NET [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))] + [RuntimeAsyncMethodGeneration(false)] #endif static async ValueTask Core(StreamPipeReader reader, int? minimumSize, CancellationTokenSource tokenSource, CancellationToken cancellationToken) { diff --git a/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/StreamPipeWriter.cs b/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/StreamPipeWriter.cs index 81ceb5484d12dd..874461af3363f5 100644 --- a/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/StreamPipeWriter.cs +++ b/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/StreamPipeWriter.cs @@ -288,6 +288,7 @@ private void Cancel() #if NET [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))] + [RuntimeAsyncMethodGeneration(false)] #endif private async ValueTask FlushAsyncInternal(bool writeToStream, ReadOnlyMemory data, CancellationToken cancellationToken = default) { diff --git a/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj b/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj index 280212748fd613..896e706663e727 100644 --- a/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj +++ b/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj @@ -112,6 +112,8 @@ Link="Common\Interop\Windows\Interop.GetCurrentThreadId.cs" /> + diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index f973fa8499005b..c2a4d472ccaa09 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -126,6 +126,8 @@ + ReadBufferedAsync(Memory destination) } [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))] + [RuntimeAsyncMethodGeneration(false)] private async ValueTask ReadBufferedAsyncCore(Memory destination) { // This is called when reading the response body. diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RawConnectionStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RawConnectionStream.cs index 15ff3ad465511c..dd572897e0d59d 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RawConnectionStream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RawConnectionStream.cs @@ -42,6 +42,7 @@ public override int Read(Span buffer) } [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))] + [RuntimeAsyncMethodGeneration(false)] public override async ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken) { CancellationHelper.ThrowIfCancellationRequested(cancellationToken); diff --git a/src/libraries/System.Net.Security/src/System.Net.Security.csproj b/src/libraries/System.Net.Security/src/System.Net.Security.csproj index 1b208fca00a699..577bcccf801c5d 100644 --- a/src/libraries/System.Net.Security/src/System.Net.Security.csproj +++ b/src/libraries/System.Net.Security/src/System.Net.Security.csproj @@ -34,6 +34,8 @@ Link="Common\System\LocalAppContextSwitches.Common.cs" /> + diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs index 9ee1c4519b234f..a2c1aa1200bfec 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.IO.cs @@ -791,6 +791,7 @@ private bool HaveFullTlsFrame(out int frameSize) } [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))] + [RuntimeAsyncMethodGeneration(false)] private async ValueTask EnsureFullTlsFrameAsync(CancellationToken cancellationToken, int estimatedSize) where TIOAdapter : IReadWriteAdapter { @@ -839,6 +840,7 @@ private async ValueTask EnsureFullTlsFrameAsync(CancellationTok } [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))] + [RuntimeAsyncMethodGeneration(false)] private async ValueTask ReadAsyncInternal(Memory buffer, CancellationToken cancellationToken) where TIOAdapter : IReadWriteAdapter { diff --git a/src/libraries/System.Net.WebSockets/src/System.Net.WebSockets.csproj b/src/libraries/System.Net.WebSockets/src/System.Net.WebSockets.csproj index 4b1229be09da56..6725eba0e435fb 100644 --- a/src/libraries/System.Net.WebSockets/src/System.Net.WebSockets.csproj +++ b/src/libraries/System.Net.WebSockets/src/System.Net.WebSockets.csproj @@ -52,6 +52,8 @@ Link="Common\System\Net\Logging\NetEventSource.Common.cs" /> + diff --git a/src/libraries/System.Net.WebSockets/src/System/Net/WebSockets/ManagedWebSocket.cs b/src/libraries/System.Net.WebSockets/src/System/Net/WebSockets/ManagedWebSocket.cs index 388c660cd01d39..47188efe5cfd7f 100644 --- a/src/libraries/System.Net.WebSockets/src/System/Net/WebSockets/ManagedWebSocket.cs +++ b/src/libraries/System.Net.WebSockets/src/System/Net/WebSockets/ManagedWebSocket.cs @@ -771,6 +771,7 @@ private static void WriteRandomMask(byte[] buffer, int offset) => /// The CancellationToken used to cancel the websocket. /// Information about the received message. [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))] + [RuntimeAsyncMethodGeneration(false)] private async ValueTask ReceiveAsyncPrivate(Memory payloadBuffer, CancellationToken cancellationToken) { // This is a long method. While splitting it up into pieces would arguably help with readability, doing so would @@ -1599,6 +1600,7 @@ private void ConsumeFromBuffer(int count) } [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder))] + [RuntimeAsyncMethodGeneration(false)] private async ValueTask EnsureBufferContainsAsync(int minimumRequiredBytes, CancellationToken cancellationToken) { Debug.Assert(minimumRequiredBytes <= _receiveBuffer.Length, $"Requested number of bytes {minimumRequiredBytes} must not exceed {_receiveBuffer.Length}"); diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 8e32c60707ae49..cad21cc174fce8 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1560,6 +1560,9 @@ Common\System\Reflection\Metadata\TypeNameParserHelpers.cs + + Common\System\Runtime\CompilerServices\RuntimeAsyncMethodGenerationAttribute.cs + Common\System\Runtime\Versioning\NonVersionableAttribute.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/BufferedFileStreamStrategy.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/BufferedFileStreamStrategy.cs index 090f595db1097e..cfdbd596199ade 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/BufferedFileStreamStrategy.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/BufferedFileStreamStrategy.cs @@ -388,6 +388,7 @@ private async ValueTask ReadFromNonSeekableAsync(Memory destination, } [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))] + [RuntimeAsyncMethodGeneration(false)] private async ValueTask ReadAsyncSlowPath(Task semaphoreLockTask, Memory buffer, CancellationToken cancellationToken) { Debug.Assert(_asyncActiveSemaphore != null); @@ -671,6 +672,7 @@ private async ValueTask WriteToNonSeekableAsync(ReadOnlyMemory source, Can } [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder))] + [RuntimeAsyncMethodGeneration(false)] private async ValueTask WriteAsyncSlowPath(Task semaphoreLockTask, ReadOnlyMemory source, CancellationToken cancellationToken) { Debug.Assert(_asyncActiveSemaphore != null); diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Stream.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Stream.cs index b99ff4886eb0be..b04fae4200e37e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/Stream.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/Stream.cs @@ -424,6 +424,7 @@ public ValueTask ReadAtLeastAsync(Memory buffer, int minimumBytes, bo // No argument checking is done here. It is up to the caller. [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))] + [RuntimeAsyncMethodGeneration(false)] private async ValueTask ReadAtLeastAsyncCore(Memory buffer, int minimumBytes, bool throwOnEndOfStream, CancellationToken cancellationToken) { Debug.Assert(minimumBytes <= buffer.Length);