3
3
4
4
using System . Runtime . InteropServices ;
5
5
using System . Threading . Tasks ;
6
- using Internal . Runtime . CompilerServices ;
7
-
8
- using StateMachineBox = System . Runtime . CompilerServices . AsyncValueTaskMethodBuilder < System . Threading . Tasks . VoidTaskResult > . StateMachineBox ;
9
6
10
7
namespace System . Runtime . CompilerServices
11
8
{
12
9
/// <summary>Represents a builder for asynchronous methods that return a <see cref="ValueTask"/>.</summary>
13
10
[ StructLayout ( LayoutKind . Auto ) ]
14
11
public struct AsyncValueTaskMethodBuilder
15
12
{
16
- /// <summary>true if we should use reusable boxes for async completions of ValueTask methods; false if we should use tasks.</summary>
17
- /// <remarks>
18
- /// We rely on tiered compilation turning this into a const and doing dead code elimination to make checks on this efficient.
19
- /// It's also required for safety that this value never changes once observed, as Unsafe.As casts are employed based on its value.
20
- /// </remarks>
21
- internal static readonly bool s_valueTaskPoolingEnabled = GetPoolAsyncValueTasksSwitch ( ) ;
22
- /// <summary>Maximum number of boxes that are allowed to be cached per state machine type.</summary>
23
- internal static readonly int s_valueTaskPoolingCacheSize = GetPoolAsyncValueTasksLimitValue ( ) ;
24
-
25
13
/// <summary>Sentinel object used to indicate that the builder completed synchronously and successfully.</summary>
26
- private static readonly object s_syncSuccessSentinel = AsyncValueTaskMethodBuilder < VoidTaskResult > . s_syncSuccessSentinel ;
14
+ private static readonly Task < VoidTaskResult > s_syncSuccessSentinel = AsyncValueTaskMethodBuilder < VoidTaskResult > . s_syncSuccessSentinel ;
27
15
28
- /// <summary>The wrapped state machine box or task, based on the value of <see cref="s_valueTaskPoolingEnabled"/> .</summary>
16
+ /// <summary>The wrapped task.</summary>
29
17
/// <remarks>
30
18
/// If the operation completed synchronously and successfully, this will be <see cref="s_syncSuccessSentinel"/>.
31
19
/// </remarks>
32
- private object ? m_task ; // Debugger depends on the exact name of this field.
20
+ private Task < VoidTaskResult > ? m_task ; // Debugger depends on the exact name of this field.
33
21
34
22
/// <summary>Creates an instance of the <see cref="AsyncValueTaskMethodBuilder"/> struct.</summary>
35
23
/// <returns>The initialized instance.</returns>
@@ -39,8 +27,7 @@ public struct AsyncValueTaskMethodBuilder
39
27
/// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
40
28
/// <param name="stateMachine">The state machine instance, passed by reference.</param>
41
29
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
42
- public void Start < TStateMachine > ( ref TStateMachine stateMachine )
43
- where TStateMachine : IAsyncStateMachine =>
30
+ public void Start < TStateMachine > ( ref TStateMachine stateMachine ) where TStateMachine : IAsyncStateMachine =>
44
31
AsyncMethodBuilderCore . Start ( ref stateMachine ) ;
45
32
46
33
/// <summary>Associates the builder with the specified state machine.</summary>
@@ -55,29 +42,16 @@ public void SetResult()
55
42
{
56
43
m_task = s_syncSuccessSentinel ;
57
44
}
58
- else if ( s_valueTaskPoolingEnabled )
59
- {
60
- Unsafe . As < StateMachineBox > ( m_task ) . SetResult ( default ) ;
61
- }
62
45
else
63
46
{
64
- AsyncTaskMethodBuilder < VoidTaskResult > . SetExistingTaskResult ( Unsafe . As < Task < VoidTaskResult > > ( m_task ) , default ) ;
47
+ AsyncTaskMethodBuilder < VoidTaskResult > . SetExistingTaskResult ( m_task , default ) ;
65
48
}
66
49
}
67
50
68
51
/// <summary>Marks the task as failed and binds the specified exception to the task.</summary>
69
52
/// <param name="exception">The exception to bind to the task.</param>
70
- public void SetException ( Exception exception )
71
- {
72
- if ( s_valueTaskPoolingEnabled )
73
- {
74
- AsyncValueTaskMethodBuilder < VoidTaskResult > . SetException ( exception , ref Unsafe . As < object ? , StateMachineBox ? > ( ref m_task ) ) ;
75
- }
76
- else
77
- {
78
- AsyncTaskMethodBuilder < VoidTaskResult > . SetException ( exception , ref Unsafe . As < object ? , Task < VoidTaskResult > ? > ( ref m_task ) ) ;
79
- }
80
- }
53
+ public void SetException ( Exception exception ) =>
54
+ AsyncTaskMethodBuilder < VoidTaskResult > . SetException ( exception , ref m_task ) ;
81
55
82
56
/// <summary>Gets the task for this builder.</summary>
83
57
public ValueTask Task
@@ -94,27 +68,11 @@ public ValueTask Task
94
68
// or it should be completing asynchronously, in which case AwaitUnsafeOnCompleted would have similarly
95
69
// initialized m_task to a state machine object. However, if the type is used manually (not via
96
70
// compiler-generated code) and accesses Task directly, we force it to be initialized. Things will then
97
- // "work" but in a degraded mode, as we don't know the TStateMachine type here, and thus we use a box around
98
- // the interface instead.
71
+ // "work" but in a degraded mode, as we don't know the TStateMachine type here, and thus we use a normal
72
+ // task object instead.
99
73
100
- if ( s_valueTaskPoolingEnabled )
101
- {
102
- var box = Unsafe . As < StateMachineBox ? > ( m_task ) ;
103
- if ( box is null )
104
- {
105
- m_task = box = AsyncValueTaskMethodBuilder < VoidTaskResult > . CreateWeaklyTypedStateMachineBox ( ) ;
106
- }
107
- return new ValueTask ( box , box . Version ) ;
108
- }
109
- else
110
- {
111
- var task = Unsafe . As < Task < VoidTaskResult > ? > ( m_task ) ;
112
- if ( task is null )
113
- {
114
- m_task = task = new Task < VoidTaskResult > ( ) ; // base task used rather than box to minimize size when used as manual promise
115
- }
116
- return new ValueTask ( task ) ;
117
- }
74
+ Task < VoidTaskResult > ? task = m_task ??= new Task < VoidTaskResult > ( ) ; // base task used rather than box to minimize size when used as manual promise
75
+ return new ValueTask ( task ) ;
118
76
}
119
77
}
120
78
@@ -125,17 +83,8 @@ public ValueTask Task
125
83
/// <param name="stateMachine">The state machine.</param>
126
84
public void AwaitOnCompleted < TAwaiter , TStateMachine > ( ref TAwaiter awaiter , ref TStateMachine stateMachine )
127
85
where TAwaiter : INotifyCompletion
128
- where TStateMachine : IAsyncStateMachine
129
- {
130
- if ( s_valueTaskPoolingEnabled )
131
- {
132
- AsyncValueTaskMethodBuilder < VoidTaskResult > . AwaitOnCompleted ( ref awaiter , ref stateMachine , ref Unsafe . As < object ? , StateMachineBox ? > ( ref m_task ) ) ;
133
- }
134
- else
135
- {
136
- AsyncTaskMethodBuilder < VoidTaskResult > . AwaitOnCompleted ( ref awaiter , ref stateMachine , ref Unsafe . As < object ? , Task < VoidTaskResult > ? > ( ref m_task ) ) ;
137
- }
138
- }
86
+ where TStateMachine : IAsyncStateMachine =>
87
+ AsyncTaskMethodBuilder < VoidTaskResult > . AwaitOnCompleted ( ref awaiter , ref stateMachine , ref m_task ) ;
139
88
140
89
/// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary>
141
90
/// <typeparam name="TAwaiter">The type of the awaiter.</typeparam>
@@ -145,17 +94,8 @@ public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref
145
94
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
146
95
public void AwaitUnsafeOnCompleted < TAwaiter , TStateMachine > ( ref TAwaiter awaiter , ref TStateMachine stateMachine )
147
96
where TAwaiter : ICriticalNotifyCompletion
148
- where TStateMachine : IAsyncStateMachine
149
- {
150
- if ( s_valueTaskPoolingEnabled )
151
- {
152
- AsyncValueTaskMethodBuilder < VoidTaskResult > . AwaitUnsafeOnCompleted ( ref awaiter , ref stateMachine , ref Unsafe . As < object ? , StateMachineBox ? > ( ref m_task ) ) ;
153
- }
154
- else
155
- {
156
- AsyncTaskMethodBuilder < VoidTaskResult > . AwaitUnsafeOnCompleted ( ref awaiter , ref stateMachine , ref Unsafe . As < object ? , Task < VoidTaskResult > ? > ( ref m_task ) ) ;
157
- }
158
- }
97
+ where TStateMachine : IAsyncStateMachine =>
98
+ AsyncTaskMethodBuilder < VoidTaskResult > . AwaitUnsafeOnCompleted ( ref awaiter , ref stateMachine , ref m_task ) ;
159
99
160
100
/// <summary>
161
101
/// Gets an object that may be used to uniquely identify this builder to the debugger.
@@ -165,28 +105,6 @@ public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter
165
105
/// It must only be used by the debugger and tracing purposes, and only in a single-threaded manner
166
106
/// when no other threads are in the middle of accessing this or other members that lazily initialize the box.
167
107
/// </remarks>
168
- internal object ObjectIdForDebugger
169
- {
170
- get
171
- {
172
- if ( m_task is null )
173
- {
174
- m_task = s_valueTaskPoolingEnabled ? ( object )
175
- AsyncValueTaskMethodBuilder < VoidTaskResult > . CreateWeaklyTypedStateMachineBox ( ) :
176
- AsyncTaskMethodBuilder < VoidTaskResult > . CreateWeaklyTypedStateMachineBox ( ) ;
177
- }
178
-
179
- return m_task ;
180
- }
181
- }
182
-
183
- private static bool GetPoolAsyncValueTasksSwitch ( ) =>
184
- Environment . GetEnvironmentVariable ( "DOTNET_SYSTEM_THREADING_POOLASYNCVALUETASKS" ) is string value &&
185
- ( bool . IsTrueStringIgnoreCase ( value ) || value == "1" ) ;
186
-
187
- private static int GetPoolAsyncValueTasksLimitValue ( ) =>
188
- int . TryParse ( Environment . GetEnvironmentVariable ( "DOTNET_SYSTEM_THREADING_POOLASYNCVALUETASKSLIMIT" ) , out int result ) && result > 0 ?
189
- result :
190
- Environment . ProcessorCount * 4 ; // arbitrary default value
108
+ internal object ObjectIdForDebugger => m_task ??= AsyncTaskMethodBuilder < VoidTaskResult > . CreateWeaklyTypedStateMachineBox ( ) ;
191
109
}
192
110
}
0 commit comments