1- using JetBrains . Annotations ;
2- using System ;
3- using System . Diagnostics ;
4- using System . Runtime . ExceptionServices ;
5- using System . Threading ;
1+ using System ;
62using System . Threading . Tasks ;
73using System . Threading . Tasks . Sources ;
84
@@ -13,140 +9,49 @@ namespace BenchmarkDotNet.Helpers
139 /// </summary>
1410 public class AutoResetValueTaskSource < TResult > : IValueTaskSource < TResult > , IValueTaskSource
1511 {
16- [ CanBeNull ] private Action < object > _continuation ;
17- [ CanBeNull ] private object _continuationState ;
18- private bool _completed ;
19- [ CanBeNull ] private TResult _result ;
20- [ CanBeNull ] private ExceptionDispatchInfo _error ;
21- private short _version ;
22-
23- private void Reset ( )
24- {
25- // Reset/update state for the next use/await of this instance.
26- _version ++ ;
27- _completed = false ;
28- _result = default ;
29- _error = null ;
30- _continuation = null ;
31- _continuationState = null ;
32- }
12+ private ManualResetValueTaskSourceCore < TResult > _sourceCore ;
3313
3414 /// <summary>Completes with a successful result.</summary>
3515 /// <param name="result">The result.</param>
36- public void SetResult ( TResult result )
37- {
38- _result = result ;
39- SignalCompletion ( ) ;
40- }
16+ public void SetResult ( TResult result ) => _sourceCore . SetResult ( result ) ;
4117
4218 /// <summary>Completes with an error.</summary>
4319 /// <param name="error">The exception.</param>
44- public void SetException ( Exception error )
45- {
46- _error = ExceptionDispatchInfo . Capture ( error ) ;
47- SignalCompletion ( ) ;
48- }
20+ public void SetException ( Exception error ) => _sourceCore . SetException ( error ) ;
4921
5022 /// <summary>Gets the operation version.</summary>
51- public short Version => _version ;
23+ public short Version => _sourceCore . Version ;
5224
5325 /// <summary>Gets the status of the operation.</summary>
5426 /// <param name="token">Opaque value that was provided to the <see cref="ValueTask"/>'s constructor.</param>
55- public ValueTaskSourceStatus GetStatus ( short token )
56- {
57- ValidateToken ( token ) ;
58- return
59- _continuation == null || ! _completed ? ValueTaskSourceStatus . Pending :
60- _error == null ? ValueTaskSourceStatus . Succeeded :
61- _error . SourceException is OperationCanceledException ? ValueTaskSourceStatus . Canceled :
62- ValueTaskSourceStatus . Faulted ;
63- }
27+ public ValueTaskSourceStatus GetStatus ( short token ) => _sourceCore . GetStatus ( token ) ;
6428
6529 /// <summary>Gets the result of the operation.</summary>
6630 /// <param name="token">Opaque value that was provided to the <see cref="ValueTask"/>'s constructor.</param>
6731 public TResult GetResult ( short token )
6832 {
69- ValidateToken ( token ) ;
70- if ( ! _completed )
33+ // We don't want to reset this if the token is invalid.
34+ if ( token != Version )
7135 {
7236 throw new InvalidOperationException ( ) ;
7337 }
74-
75- var result = _result ;
76- var error = _error ;
77- Reset ( ) ;
78- error ? . Throw ( ) ;
79- return result ;
80- }
81-
82- public void OnCompleted ( Action < object > continuation , object state , short token , ValueTaskSourceOnCompletedFlags flags )
83- {
84- if ( continuation == null )
85- {
86- throw new ArgumentNullException ( nameof ( continuation ) ) ;
87- }
88- ValidateToken ( token ) ;
89-
90- // We need to set the continuation state before we swap in the delegate, so that
91- // if there's a race between this and SetResult/Exception and SetResult/Exception
92- // sees the _continuation as non-null, it'll be able to invoke it with the state
93- // stored here. However, this also means that if this is used incorrectly (e.g.
94- // awaited twice concurrently), _continuationState might get erroneously overwritten.
95- // To minimize the chances of that, we check preemptively whether _continuation
96- // is already set to something other than the completion sentinel.
97-
98- object oldContinuation = _continuation ;
99- if ( oldContinuation == null )
38+ try
10039 {
101- _continuationState = state ;
102- oldContinuation = Interlocked . CompareExchange ( ref _continuation , continuation , null ) ;
40+ return _sourceCore . GetResult ( token ) ;
10341 }
104-
105- if ( oldContinuation != null )
42+ finally
10643 {
107- // Operation already completed, so we need to call the supplied callback.
108- if ( ! ReferenceEquals ( oldContinuation , AutoResetValueTaskSourceCoreShared . s_sentinel ) )
109- {
110- throw new InvalidOperationException ( ) ;
111- }
112-
113- continuation ( state ) ;
44+ _sourceCore . Reset ( ) ;
11445 }
11546 }
11647
117- private void ValidateToken ( short token )
118- {
119- if ( token != _version )
120- {
121- throw new InvalidOperationException ( ) ;
122- }
123- }
124-
125- private void SignalCompletion ( )
126- {
127- if ( _completed )
128- {
129- throw new InvalidOperationException ( ) ;
130- }
131- _completed = true ;
132-
133- Interlocked . CompareExchange ( ref _continuation , AutoResetValueTaskSourceCoreShared . s_sentinel , null )
134- ? . Invoke ( _continuationState ) ;
135- }
136-
137- void IValueTaskSource . GetResult ( short token )
138- {
139- GetResult ( token ) ;
140- }
141- }
48+ /// <summary>Schedules the continuation action for this operation.</summary>
49+ /// <param name="continuation">The continuation to invoke when the operation has completed.</param>
50+ /// <param name="state">The state object to pass to <paramref name="continuation"/> when it's invoked.</param>
51+ /// <param name="token">Opaque value that was provided to the <see cref="ValueTask"/>'s constructor.</param>
52+ /// <param name="flags">The flags describing the behavior of the continuation.</param>
53+ public void OnCompleted ( Action < object > continuation , object state , short token , ValueTaskSourceOnCompletedFlags flags ) => _sourceCore . OnCompleted ( continuation , state , token , flags ) ;
14254
143- internal static class AutoResetValueTaskSourceCoreShared // separated out of generic to avoid unnecessary duplication
144- {
145- internal static readonly Action < object > s_sentinel = CompletionSentinel ;
146- private static void CompletionSentinel ( object _ ) // named method to aid debugging
147- {
148- Debug . Fail ( "The sentinel delegate should never be invoked." ) ;
149- throw new InvalidOperationException ( ) ;
150- }
55+ void IValueTaskSource . GetResult ( short token ) => GetResult ( token ) ;
15156 }
15257}
0 commit comments