@@ -39,9 +39,17 @@ public abstract class CompletionSource
3939
4040 public sealed class CompletionSource < T > : CompletionSource
4141 {
42- AsyncValueTaskMethodBuilder < T > _amb = AsyncValueTaskMethodBuilder < T > . Create ( ) ;
42+ AsyncValueTaskMethodBuilder < T > _amb ;
4343
44- public ValueTask < T > Task => _amb . Task ;
44+ public ValueTask < T > Task { get ; }
45+
46+ public CompletionSource ( )
47+ {
48+ _amb = AsyncValueTaskMethodBuilder < T > . Create ( ) ;
49+ // AsyncValueTaskMethodBuilder's Task and SetResult aren't thread safe in regard to each other
50+ // Which is why we access it prematurely
51+ Task = _amb . Task ;
52+ }
4553
4654 public void SetResult ( T value )
4755 => _amb . SetResult ( value ) ;
@@ -53,11 +61,23 @@ public override void SetException(Exception exception)
5361 public sealed class PoolingCompletionSource < T > : CompletionSource
5462 {
5563#if NETSTANDARD
56- AsyncValueTaskMethodBuilder < T > _amb = AsyncValueTaskMethodBuilder < T > . Create ( ) ;
64+ AsyncValueTaskMethodBuilder < T > _amb ;
5765#else
58- PoolingAsyncValueTaskMethodBuilder < T > _amb = PoolingAsyncValueTaskMethodBuilder < T > . Create ( ) ;
66+ PoolingAsyncValueTaskMethodBuilder < T > _amb ;
5967#endif
60- public ValueTask < T > Task => _amb . Task ;
68+ public ValueTask < T > Task { get ; }
69+
70+ public PoolingCompletionSource ( )
71+ {
72+ #if NETSTANDARD
73+ _amb = AsyncValueTaskMethodBuilder < T > . Create ( ) ;
74+ #else
75+ _amb = PoolingAsyncValueTaskMethodBuilder < T > . Create ( ) ;
76+ #endif
77+ // PoolingAsyncValueTaskMethodBuilder's Task and SetResult aren't thread safe in regard to each other
78+ // Which is why we access it prematurely
79+ Task = _amb . Task ;
80+ }
6181
6282 public void SetResult ( T value )
6383 => _amb . SetResult ( value ) ;
@@ -95,7 +115,7 @@ public CompletionSourceContinuation(object handle, delegate*<Task, CompletionSou
95115 if ( task . IsCompletedSuccessfully )
96116 return new ( new T ? ( task . Result ) ) ;
97117
98- // Otherwise we do one additional allocation, this allow us to share state machine codegen for all Ts.
118+ // Otherwise we do one additional allocation, this allows us to share state machine codegen for all Ts.
99119 var source = new PoolingCompletionSource < T ? > ( ) ;
100120 OnCompletedWithSource ( task . AsTask ( ) , source , new ( instance , & UnboxAndComplete ) ) ;
101121 return source . Task ;
@@ -116,7 +136,7 @@ public static unsafe ValueTask<T> ReadAsObjectAsyncAsT<T>(this PgConverter<T> in
116136 if ( task . IsCompletedSuccessfully )
117137 return new ( ( T ) task . Result ) ;
118138
119- // Otherwise we do one additional allocation, this allow us to share state machine codegen for all Ts.
139+ // Otherwise we do one additional allocation, this allows us to share state machine codegen for all Ts.
120140 var source = new PoolingCompletionSource < T > ( ) ;
121141 OnCompletedWithSource ( task . AsTask ( ) , source , new ( instance , & UnboxAndComplete ) ) ;
122142 return source . Task ;
0 commit comments