Skip to content

Commit b3a7a80

Browse files
committed
Use ManualResetValueTaskSourceCore instead of copying source code.
1 parent 44f986f commit b3a7a80

File tree

1 file changed

+19
-114
lines changed

1 file changed

+19
-114
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
using JetBrains.Annotations;
2-
using System;
3-
using System.Diagnostics;
4-
using System.Runtime.ExceptionServices;
5-
using System.Threading;
1+
using System;
62
using System.Threading.Tasks;
73
using 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

Comments
 (0)