1
- using JetBrains . Annotations ;
2
- using System ;
3
- using System . Diagnostics ;
4
- using System . Runtime . ExceptionServices ;
5
- using System . Threading ;
1
+ using System ;
6
2
using System . Threading . Tasks ;
7
3
using System . Threading . Tasks . Sources ;
8
4
@@ -13,140 +9,49 @@ namespace BenchmarkDotNet.Helpers
13
9
/// </summary>
14
10
public class AutoResetValueTaskSource < TResult > : IValueTaskSource < TResult > , IValueTaskSource
15
11
{
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 ;
33
13
34
14
/// <summary>Completes with a successful result.</summary>
35
15
/// <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 ) ;
41
17
42
18
/// <summary>Completes with an error.</summary>
43
19
/// <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 ) ;
49
21
50
22
/// <summary>Gets the operation version.</summary>
51
- public short Version => _version ;
23
+ public short Version => _sourceCore . Version ;
52
24
53
25
/// <summary>Gets the status of the operation.</summary>
54
26
/// <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 ) ;
64
28
65
29
/// <summary>Gets the result of the operation.</summary>
66
30
/// <param name="token">Opaque value that was provided to the <see cref="ValueTask"/>'s constructor.</param>
67
31
public TResult GetResult ( short token )
68
32
{
69
- ValidateToken ( token ) ;
70
- if ( ! _completed )
33
+ // We don't want to reset this if the token is invalid.
34
+ if ( token != Version )
71
35
{
72
36
throw new InvalidOperationException ( ) ;
73
37
}
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
100
39
{
101
- _continuationState = state ;
102
- oldContinuation = Interlocked . CompareExchange ( ref _continuation , continuation , null ) ;
40
+ return _sourceCore . GetResult ( token ) ;
103
41
}
104
-
105
- if ( oldContinuation != null )
42
+ finally
106
43
{
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 ( ) ;
114
45
}
115
46
}
116
47
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 ) ;
142
54
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 ) ;
151
56
}
152
57
}
0 commit comments