Skip to content

Commit 2cbdf2c

Browse files
committed
Changed ManualResetValueTaskSource to AutoResetValueTaskSource.
1 parent 72602a1 commit 2cbdf2c

5 files changed

Lines changed: 42 additions & 88 deletions

File tree

src/BenchmarkDotNet/Helpers/ManualResetValueTaskSource.cs renamed to src/BenchmarkDotNet/Helpers/AutoResetValueTaskSource.cs

Lines changed: 16 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,26 @@
1-
// Licensed to the .NET Foundation under one or more agreements.
2-
// The .NET Foundation licenses this file to you under the MIT license.
3-
4-
using JetBrains.Annotations;
1+
using JetBrains.Annotations;
52
using System;
63
using System.Diagnostics;
74
using System.Runtime.ExceptionServices;
8-
using System.Runtime.InteropServices;
95
using System.Threading;
6+
using System.Threading.Tasks;
107
using System.Threading.Tasks.Sources;
118

129
namespace BenchmarkDotNet.Helpers
1310
{
14-
/// <summary>Provides the core logic for implementing a manual-reset <see cref="IValueTaskSource"/> or <see cref="IValueTaskSource{TResult}"/>.</summary>
15-
/// <typeparam name="TResult"></typeparam>
16-
[StructLayout(LayoutKind.Auto)]
17-
public class ManualResetValueTaskSource<TResult> : IValueTaskSource<TResult>, IValueTaskSource
11+
/// <summary>
12+
/// Implementation for <see cref="IValueTaskSource{TResult}"/> that will reset itself when awaited so that it can be re-used.
13+
/// </summary>
14+
public class AutoResetValueTaskSource<TResult> : IValueTaskSource<TResult>, IValueTaskSource
1815
{
19-
/// <summary>
20-
/// The callback to invoke when the operation completes if <see cref="OnCompleted"/> was called before the operation completed,
21-
/// or <see cref="ManualResetValueTaskSourceCoreShared.s_sentinel"/> if the operation completed before a callback was supplied,
22-
/// or null if a callback hasn't yet been provided and the operation hasn't yet completed.
23-
/// </summary>
2416
[CanBeNull] private Action<object> _continuation;
25-
/// <summary>State to pass to <see cref="_continuation"/>.</summary>
2617
[CanBeNull] private object _continuationState;
27-
/// <summary>Whether the current operation has completed.</summary>
2818
private bool _completed;
29-
/// <summary>The result with which the operation succeeded, or the default value if it hasn't yet completed or failed.</summary>
3019
[CanBeNull] private TResult _result;
31-
/// <summary>The exception with which the operation failed, or null if it hasn't yet completed or completed successfully.</summary>
3220
[CanBeNull] private ExceptionDispatchInfo _error;
33-
/// <summary>The current version of this value, used to help prevent misuse.</summary>
3421
private short _version;
3522

36-
/// <summary>Resets to prepare for the next operation.</summary>
37-
public void Reset()
23+
private void Reset()
3824
{
3925
// Reset/update state for the next use/await of this instance.
4026
_version++;
@@ -86,8 +72,11 @@ public TResult GetResult(short token)
8672
throw new InvalidOperationException();
8773
}
8874

89-
_error?.Throw();
90-
return _result;
75+
var result = _result;
76+
var error = _error;
77+
Reset();
78+
error?.Throw();
79+
return result;
9180
}
9281

9382
public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)
@@ -116,7 +105,7 @@ public void OnCompleted(Action<object> continuation, object state, short token,
116105
if (oldContinuation != null)
117106
{
118107
// Operation already completed, so we need to call the supplied callback.
119-
if (!ReferenceEquals(oldContinuation, ManualResetValueTaskSourceCoreShared.s_sentinel))
108+
if (!ReferenceEquals(oldContinuation, AutoResetValueTaskSourceCoreShared.s_sentinel))
120109
{
121110
throw new InvalidOperationException();
122111
}
@@ -125,8 +114,6 @@ public void OnCompleted(Action<object> continuation, object state, short token,
125114
}
126115
}
127116

128-
/// <summary>Ensures that the specified token matches the current version.</summary>
129-
/// <param name="token">The token supplied by <see cref="ValueTask"/>.</param>
130117
private void ValidateToken(short token)
131118
{
132119
if (token != _version)
@@ -135,7 +122,6 @@ private void ValidateToken(short token)
135122
}
136123
}
137124

138-
/// <summary>Signals that the operation has completed. Invoked after the result or error has been set.</summary>
139125
private void SignalCompletion()
140126
{
141127
if (_completed)
@@ -144,21 +130,8 @@ private void SignalCompletion()
144130
}
145131
_completed = true;
146132

147-
if (_continuation != null || Interlocked.CompareExchange(ref _continuation, ManualResetValueTaskSourceCoreShared.s_sentinel, null) != null)
148-
{
149-
InvokeContinuation();
150-
}
151-
}
152-
153-
/// <summary>
154-
/// Invokes the continuation with the appropriate captured context / scheduler.
155-
/// This assumes that if <see cref="_executionContext"/> is not null we're already
156-
/// running within that <see cref="ExecutionContext"/>.
157-
/// </summary>
158-
private void InvokeContinuation()
159-
{
160-
Debug.Assert(_continuation != null);
161-
_continuation(_continuationState);
133+
Interlocked.CompareExchange(ref _continuation, AutoResetValueTaskSourceCoreShared.s_sentinel, null)
134+
?.Invoke(_continuationState);
162135
}
163136

164137
void IValueTaskSource.GetResult(short token)
@@ -167,7 +140,7 @@ void IValueTaskSource.GetResult(short token)
167140
}
168141
}
169142

170-
internal static class ManualResetValueTaskSourceCoreShared // separated out of generic to avoid unnecessary duplication
143+
internal static class AutoResetValueTaskSourceCoreShared // separated out of generic to avoid unnecessary duplication
171144
{
172145
internal static readonly Action<object> s_sentinel = CompletionSentinel;
173146
private static void CompletionSentinel(object _) // named method to aid debugging

src/BenchmarkDotNet/Templates/BenchmarkType.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@
114114

115115
#if RETURNS_AWAITABLE_$ID$
116116

117-
private readonly BenchmarkDotNet.Helpers.ManualResetValueTaskSource<Perfolizer.Horology.ClockSpan> valueTaskSource = new BenchmarkDotNet.Helpers.ManualResetValueTaskSource<Perfolizer.Horology.ClockSpan>();
117+
private readonly BenchmarkDotNet.Helpers.AutoResetValueTaskSource<Perfolizer.Horology.ClockSpan> valueTaskSource = new BenchmarkDotNet.Helpers.AutoResetValueTaskSource<Perfolizer.Horology.ClockSpan>();
118118
private System.Int64 repeatsRemaining;
119119
private readonly System.Action continuation;
120120
private Perfolizer.Horology.StartedClock startedClock;
@@ -183,7 +183,6 @@
183183
private System.Threading.Tasks.ValueTask<Perfolizer.Horology.ClockSpan> WorkloadActionImpl(System.Int64 invokeCount, Perfolizer.Horology.IClock clock)
184184
{
185185
repeatsRemaining = invokeCount;
186-
valueTaskSource.Reset();
187186
startedClock = Perfolizer.Horology.ClockExtensions.Start(clock);
188187
__RunTask();
189188
return new System.Threading.Tasks.ValueTask<Perfolizer.Horology.ClockSpan>(valueTaskSource, valueTaskSource.Version);

src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Emitters/TaskConsumeEmitter.cs

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ internal class TaskConsumeEmitter : ConsumeEmitter
1919

2020
private LocalBuilder disassemblyDiagnoserLocal;
2121
/*
22-
private readonly BenchmarkDotNet.Helpers.ManualResetValueTaskSource<Perfolizer.Horology.ClockSpan> valueTaskSource = new BenchmarkDotNet.Helpers.ManualResetValueTaskSource<Perfolizer.Horology.ClockSpan>();
22+
private readonly BenchmarkDotNet.Helpers.AutoResetValueTaskSource<Perfolizer.Horology.ClockSpan> valueTaskSource = new BenchmarkDotNet.Helpers.AutoResetValueTaskSource<Perfolizer.Horology.ClockSpan>();
2323
private System.Int64 repeatsRemaining;
2424
private readonly System.Action continuation;
2525
private Perfolizer.Horology.StartedClock startedClock;
@@ -48,7 +48,7 @@ protected override void OnDefineFieldsOverride(TypeBuilder runnableBuilder)
4848
&& !m.GetParameterTypes().First().IsByRef)
4949
.MakeGenericMethod(ConsumableInfo.OverheadMethodReturnType);
5050

51-
valueTaskSourceField = runnableBuilder.DefineField(ValueTaskSourceFieldName, typeof(Helpers.ManualResetValueTaskSource<ClockSpan>), FieldAttributes.Private | FieldAttributes.InitOnly);
51+
valueTaskSourceField = runnableBuilder.DefineField(ValueTaskSourceFieldName, typeof(Helpers.AutoResetValueTaskSource<ClockSpan>), FieldAttributes.Private | FieldAttributes.InitOnly);
5252
repeatsRemainingField = runnableBuilder.DefineField(RepeatsRemainingFieldName, typeof(long), FieldAttributes.Private);
5353
continuationField = runnableBuilder.DefineField(ContinuationFieldName, typeof(Action), FieldAttributes.Private | FieldAttributes.InitOnly);
5454
startedClockField = runnableBuilder.DefineField(StartedClockFieldName, typeof(StartedClock), FieldAttributes.Private);
@@ -72,15 +72,15 @@ protected override void EmitDisassemblyDiagnoserReturnDefaultOverride(ILGenerato
7272

7373
protected override void OnEmitCtorBodyOverride(ConstructorBuilder constructorBuilder, ILGenerator ilBuilder)
7474
{
75-
var ctor = typeof(Helpers.ManualResetValueTaskSource<ClockSpan>).GetConstructor(Array.Empty<Type>());
75+
var ctor = typeof(Helpers.AutoResetValueTaskSource<ClockSpan>).GetConstructor(Array.Empty<Type>());
7676
if (ctor == null)
77-
throw new InvalidOperationException($"Cannot get default .ctor for {typeof(Helpers.ManualResetValueTaskSource<ClockSpan>)}");
77+
throw new InvalidOperationException($"Cannot get default .ctor for {typeof(Helpers.AutoResetValueTaskSource<ClockSpan>)}");
7878

7979
/*
80-
// valueTaskSourceField = new BenchmarkDotNet.Helpers.ManualResetValueTaskSource<Perfolizer.Horology.ClockSpan>();
80+
// valueTaskSourceField = new BenchmarkDotNet.Helpers.AutoResetValueTaskSource<Perfolizer.Horology.ClockSpan>();
8181
IL_0000: ldarg.0
82-
IL_0001: newobj instance void class BenchmarkDotNet.Helpers.ManualResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan>::.ctor()
83-
IL_0006: stfld class BenchmarkDotNet.Helpers.ManualResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan> BenchmarkRunner_0::valueTaskSource
82+
IL_0001: newobj instance void class BenchmarkDotNet.Helpers.AutoResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan>::.ctor()
83+
IL_0006: stfld class BenchmarkDotNet.Helpers.AutoResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan> BenchmarkRunner_0::valueTaskSource
8484
*/
8585
ilBuilder.Emit(OpCodes.Ldarg_0);
8686
ilBuilder.Emit(OpCodes.Newobj, ctor);
@@ -293,16 +293,6 @@ class Perfolizer.Horology.IClock clock
293293
ilBuilder.Emit(OpCodes.Ldarg_0);
294294
ilBuilder.EmitLdarg(toArg);
295295
ilBuilder.Emit(OpCodes.Stfld, repeatsRemainingField);
296-
/*
297-
// valueTaskSource.Reset();
298-
IL_0007: ldarg.0
299-
IL_0008: ldfld class BenchmarkDotNet.Helpers.ManualResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan> BenchmarkRunner_0::valueTaskSource
300-
IL_000d: callvirt instance void class BenchmarkDotNet.Helpers.ManualResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan>::Reset()
301-
*/
302-
ilBuilder.Emit(OpCodes.Ldarg_0);
303-
ilBuilder.Emit(OpCodes.Ldfld, valueTaskSourceField);
304-
var resetMethod = valueTaskSourceField.FieldType.GetMethod(nameof(Helpers.ManualResetValueTaskSource<ClockSpan>.Reset), BindingFlagsPublicInstance);
305-
ilBuilder.Emit(OpCodes.Callvirt, resetMethod);
306296
/*
307297
// startedClock = Perfolizer.Horology.ClockExtensions.Start(clock);
308298
IL_0012: ldarg.0
@@ -324,18 +314,18 @@ class Perfolizer.Horology.IClock clock
324314
/*
325315
// return new System.Threading.Tasks.ValueTask<Perfolizer.Horology.ClockSpan>(valueTaskSource, valueTaskSource.Version);
326316
IL_0024: ldarg.0
327-
IL_0025: ldfld class BenchmarkDotNet.Helpers.ManualResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan> BenchmarkRunner_0::valueTaskSource
317+
IL_0025: ldfld class BenchmarkDotNet.Helpers.AutoResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan> BenchmarkRunner_0::valueTaskSource
328318
IL_002a: ldarg.0
329-
IL_002b: ldfld class BenchmarkDotNet.Helpers.ManualResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan> BenchmarkRunner_0::valueTaskSource
330-
IL_0030: callvirt instance int16 class BenchmarkDotNet.Helpers.ManualResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan>::get_Version()
319+
IL_002b: ldfld class BenchmarkDotNet.Helpers.AutoResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan> BenchmarkRunner_0::valueTaskSource
320+
IL_0030: callvirt instance int16 class BenchmarkDotNet.Helpers.AutoResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan>::get_Version()
331321
IL_0035: newobj instance void valuetype [System.Private.CoreLib]System.Threading.Tasks.ValueTask`1<valuetype Perfolizer.Horology.ClockSpan>::.ctor(class [System.Private.CoreLib]System.Threading.Tasks.Sources.IValueTaskSource`1<!0>, int16)
332322
IL_003a: ret
333323
*/
334324
ilBuilder.Emit(OpCodes.Ldarg_0);
335325
ilBuilder.Emit(OpCodes.Ldfld, valueTaskSourceField);
336326
ilBuilder.Emit(OpCodes.Ldarg_0);
337327
ilBuilder.Emit(OpCodes.Ldfld, valueTaskSourceField);
338-
var getVersionMethod = valueTaskSourceField.FieldType.GetProperty(nameof(Helpers.ManualResetValueTaskSource<ClockSpan>.Version), BindingFlagsPublicInstance).GetGetMethod(true);
328+
var getVersionMethod = valueTaskSourceField.FieldType.GetProperty(nameof(Helpers.AutoResetValueTaskSource<ClockSpan>.Version), BindingFlagsPublicInstance).GetGetMethod(true);
339329
ilBuilder.Emit(OpCodes.Callvirt, getVersionMethod);
340330
var ctor = actionMethodBuilder.ReturnType.GetConstructor(new[] { valueTaskSourceField.FieldType, getVersionMethod.ReturnType });
341331
ilBuilder.Emit(OpCodes.Newobj, ctor);
@@ -504,14 +494,14 @@ instance void __RunTask () cil managed
504494
/*
505495
// valueTaskSource.SetResult(clockspan);
506496
IL_008d: ldarg.0
507-
IL_008e: ldfld class BenchmarkDotNet.Helpers.ManualResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan> BenchmarkRunner_0::valueTaskSource
497+
IL_008e: ldfld class BenchmarkDotNet.Helpers.AutoResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan> BenchmarkRunner_0::valueTaskSource
508498
IL_0093: ldloc.0
509-
IL_0094: callvirt instance void class BenchmarkDotNet.Helpers.ManualResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan>::SetResult(!0)
499+
IL_0094: callvirt instance void class BenchmarkDotNet.Helpers.AutoResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan>::SetResult(!0)
510500
*/
511501
ilBuilder.Emit(OpCodes.Ldarg_0);
512502
ilBuilder.Emit(OpCodes.Ldfld, valueTaskSourceField);
513503
ilBuilder.EmitLdloc(clockspanLocal);
514-
ilBuilder.Emit(OpCodes.Callvirt, valueTaskSourceField.FieldType.GetMethod(nameof(Helpers.ManualResetValueTaskSource<ClockSpan>.SetResult), BindingFlagsPublicInstance));
504+
ilBuilder.Emit(OpCodes.Callvirt, valueTaskSourceField.FieldType.GetMethod(nameof(Helpers.AutoResetValueTaskSource<ClockSpan>.SetResult), BindingFlagsPublicInstance));
515505

516506
ilBuilder.MarkLabel(returnLabel);
517507
ilBuilder.Emit(OpCodes.Ret);
@@ -627,15 +617,15 @@ class [System.Private.CoreLib]System.Exception e
627617
/*
628618
// valueTaskSource.SetException(e);
629619
IL_0018: ldarg.0
630-
IL_0019: ldfld class BenchmarkDotNet.Helpers.ManualResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan> BenchmarkRunner_0::valueTaskSource
620+
IL_0019: ldfld class BenchmarkDotNet.Helpers.AutoResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan> BenchmarkRunner_0::valueTaskSource
631621
IL_001e: ldarg.1
632-
IL_001f: callvirt instance void class BenchmarkDotNet.Helpers.ManualResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan>::SetException(class [System.Private.CoreLib]System.Exception)
622+
IL_001f: callvirt instance void class BenchmarkDotNet.Helpers.AutoResetValueTaskSource`1<valuetype Perfolizer.Horology.ClockSpan>::SetException(class [System.Private.CoreLib]System.Exception)
633623
IL_0024: ret
634624
*/
635625
ilBuilder.Emit(OpCodes.Ldarg_0);
636626
ilBuilder.Emit(OpCodes.Ldfld, valueTaskSourceField);
637627
ilBuilder.EmitLdarg(exceptionArg);
638-
var setExceptionMethod = valueTaskSourceField.FieldType.GetMethod(nameof(Helpers.ManualResetValueTaskSource<ClockSpan>.SetException), BindingFlagsPublicInstance);
628+
var setExceptionMethod = valueTaskSourceField.FieldType.GetMethod(nameof(Helpers.AutoResetValueTaskSource<ClockSpan>.SetException), BindingFlagsPublicInstance);
639629
ilBuilder.Emit(OpCodes.Callvirt, setExceptionMethod);
640630
ilBuilder.Emit(OpCodes.Ret);
641631

0 commit comments

Comments
 (0)