mgravell / mgravell/PooledAwait
ValueTaskCompletionSource: ValidateOptimized called for every T
- Dominant language
- C#
- Stars
- 405
- Forks
- 25
- PR merge metrics
- No merged PRs in 30d
Description
With the current implementation, the `ValidateOptimized` method is called once for every type used as a type parameter. I suspect it only needs to be called once.
Moving most of the static members out of the `ValueTaskCompletionSource` struct would allow this:
```csharp
internal static class TaskHelper
{
#if NETSTANDARD1_3
public static readonly bool UseOptimizedPath = false;
#else
private static class TaskInternals
{
public static readonly Func, T, bool> TrySetResult = TryCreate(nameof(TrySetResult));
public static readonly Func, Exception, bool> TrySetException = TryCreate(nameof(TrySetException));
public static readonly Func, CancellationToken, bool> TrySetCanceled = TryCreate(nameof(TrySetCanceled));
[MethodImpl(MethodImplOptions.NoInlining)]
private static Func, TArg, bool> TryCreate(string methodName)
{
try
{
var method = typeof(Task).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(TArg) }, null);
return method is null ? null : (Func, TArg, bool>)Delegate.CreateDelegate(typeof(Func, TArg, bool>), method);
}
catch
{
return null;
}
}
}
public static readonly bool UseOptimizedPath = ValidateOptimized();
[MethodImpl(MethodImplOptions.NoInlining)]
private static bool ValidateOptimized()
{
try
{
if (TaskInternals.TrySetResult is null) return false;
if (TaskInternals.TrySetException is null) return false;
if (TaskInternals.TrySetCanceled is null) return false;
var task = CreateUninitializedTask();
if (task is null) return false;
if (task.IsCompleted) return false;
if (!TaskInternals.TrySetResult(task, default)) return false;
if (task.Status != TaskStatus.RanToCompletion) return false;
task = CreateUninitializedTask();
if (!TaskInternals.TrySetException(task, new InvalidOperationException())) return false;
if (!task.IsCompleted) return false;
if (!task.IsFaulted) return false;
try
{
_ = task.Result;
return false;
}
catch (AggregateException ex) when (ex.InnerException is InvalidOperationException)
{
}
return task.Exception?.InnerException is InvalidOperationException;
}
catch
{
return false;
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void SpinUntilCompleted([NotNull] Task task)
{
// Spin wait until the completion is finalized by another thread.
var sw = new SpinWait();
while (!task.IsCompleted)
{
sw.SpinOnce();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Task CreateUninitializedTask() => (Task)System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(Task));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TrySetResult(this Task task, T value)
{
bool result = TaskInternals.TrySetResult(task, value);
if (!result && !task.IsCompleted) SpinUntilCompleted(task);
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TrySetException(this Task task, Exception error)
{
bool result = TaskInternals.TrySetException(task, error);
if (!result && !task.IsCompleted) SpinUntilCompleted(task);
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TrySetCanceled(this Task task, CancellationToken cancellationToken)
{
bool result = TaskInternals.TrySetCanceled(task, cancellationToken);
if (!result && !task.IsCompleted) SpinUntilCompleted(task);
return result;
}
#endif
}
```
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by locating ValueTaskCompletionSource and its ValidateOptimized method. Compare how its static members are initialized with the proposed TaskHelper and TaskInternals structure. Done means ValidateOptimized runs once rather than once per type parameter while the optimized task completion behavior remains valid.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- backend
- Issue type
- Refactor
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100