Created
April 16, 2025 18:12
-
-
Save sebas77/9f29648610ac1ef50791321b5f0de888 to your computer and use it in GitHub Desktop.
UniTask modification to show the task name in the profiler
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma warning disable CS1591 | |
using Cysharp.Threading.Tasks.Internal; | |
using System; | |
using System.Linq; | |
using System.Diagnostics; | |
using System.Runtime.CompilerServices; | |
using Unity.Profiling; | |
namespace Cysharp.Threading.Tasks.CompilerServices | |
{ | |
// #ENABLE_IL2CPP in this file is to avoid bug of IL2CPP VM. | |
// Issue is tracked on https://issuetracker.unity3d.com/issues/il2cpp-incorrect-results-when-calling-a-method-from-outside-class-in-a-struct | |
// but currently it is labeled `Won't Fix`. | |
internal interface IStateMachineRunner | |
{ | |
Action MoveNext { get; } | |
void Return(); | |
#if ENABLE_IL2CPP | |
Action ReturnAction { get; } | |
#endif | |
} | |
internal interface IStateMachineRunnerPromise : IUniTaskSource | |
{ | |
Action MoveNext { get; } | |
UniTask Task { get; } | |
void SetResult(); | |
void SetException(Exception exception); | |
} | |
internal interface IStateMachineRunnerPromise<T> : IUniTaskSource<T> | |
{ | |
Action MoveNext { get; } | |
UniTask<T> Task { get; } | |
void SetResult(T result); | |
void SetException(Exception exception); | |
} | |
internal static class StateMachineUtility | |
{ | |
// Get AsyncStateMachine internal state to check IL2CPP bug | |
public static int GetState(IAsyncStateMachine stateMachine) | |
{ | |
var info = stateMachine.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) | |
.First(x => x.Name.EndsWith("__state")); | |
return (int)info.GetValue(stateMachine); | |
} | |
} | |
internal sealed class AsyncUniTaskVoid<TStateMachine> : IStateMachineRunner, ITaskPoolNode<AsyncUniTaskVoid<TStateMachine>>, IUniTaskSource | |
where TStateMachine : IAsyncStateMachine | |
{ | |
static TaskPool<AsyncUniTaskVoid<TStateMachine>> pool; | |
#if ENABLE_IL2CPP | |
public Action ReturnAction { get; } | |
#endif | |
TStateMachine stateMachine; | |
public Action MoveNext { get; } | |
public AsyncUniTaskVoid() | |
{ | |
MoveNext = Run; | |
#if ENABLE_IL2CPP | |
ReturnAction = Return; | |
#endif | |
profilerMarker = new ProfilerMarker(typeof(TStateMachine).FullName); | |
} | |
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunner runnerFieldRef) | |
{ | |
if (!pool.TryPop(out var result)) | |
{ | |
result = new AsyncUniTaskVoid<TStateMachine>(); | |
} | |
TaskTracker.TrackActiveTask(result, 3); | |
runnerFieldRef = result; // set runner before copied. | |
result.stateMachine = stateMachine; // copy struct StateMachine(in release build). | |
} | |
static AsyncUniTaskVoid() | |
{ | |
TaskPool.RegisterSizeGetter(typeof(AsyncUniTaskVoid<TStateMachine>), () => pool.Size); | |
} | |
AsyncUniTaskVoid<TStateMachine> nextNode; | |
public ref AsyncUniTaskVoid<TStateMachine> NextNode => ref nextNode; | |
public void Return() | |
{ | |
TaskTracker.RemoveTracking(this); | |
stateMachine = default; | |
pool.TryPush(this); | |
} | |
[DebuggerHidden] | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
void Run() | |
{ | |
using (profilerMarker.Auto() ) | |
stateMachine.MoveNext(); | |
} | |
// dummy interface implementation for TaskTracker. | |
UniTaskStatus IUniTaskSource.GetStatus(short token) | |
{ | |
return UniTaskStatus.Pending; | |
} | |
UniTaskStatus IUniTaskSource.UnsafeGetStatus() | |
{ | |
return UniTaskStatus.Pending; | |
} | |
void IUniTaskSource.OnCompleted(Action<object> continuation, object state, short token) | |
{ | |
} | |
void IUniTaskSource.GetResult(short token) | |
{ | |
} | |
ProfilerMarker profilerMarker; | |
} | |
internal sealed class AsyncUniTask<TStateMachine> : IStateMachineRunnerPromise, IUniTaskSource, ITaskPoolNode<AsyncUniTask<TStateMachine>> | |
where TStateMachine : IAsyncStateMachine | |
{ | |
static TaskPool<AsyncUniTask<TStateMachine>> pool; | |
#if ENABLE_IL2CPP | |
readonly Action returnDelegate; | |
#endif | |
public Action MoveNext { get; } | |
TStateMachine stateMachine; | |
UniTaskCompletionSourceCore<AsyncUnit> core; | |
AsyncUniTask() | |
{ | |
MoveNext = Run; | |
#if ENABLE_IL2CPP | |
returnDelegate = Return; | |
#endif | |
profilerMarker = new ProfilerMarker(typeof(TStateMachine).FullName); | |
} | |
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise runnerPromiseFieldRef) | |
{ | |
if (!pool.TryPop(out var result)) | |
{ | |
result = new AsyncUniTask<TStateMachine>(); | |
} | |
TaskTracker.TrackActiveTask(result, 3); | |
runnerPromiseFieldRef = result; // set runner before copied. | |
result.stateMachine = stateMachine; // copy struct StateMachine(in release build). | |
} | |
AsyncUniTask<TStateMachine> nextNode; | |
public ref AsyncUniTask<TStateMachine> NextNode => ref nextNode; | |
static AsyncUniTask() | |
{ | |
TaskPool.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine>), () => pool.Size); | |
} | |
void Return() | |
{ | |
TaskTracker.RemoveTracking(this); | |
core.Reset(); | |
stateMachine = default; | |
pool.TryPush(this); | |
} | |
bool TryReturn() | |
{ | |
TaskTracker.RemoveTracking(this); | |
core.Reset(); | |
stateMachine = default; | |
return pool.TryPush(this); | |
} | |
[DebuggerHidden] | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
void Run() | |
{ | |
using (profilerMarker.Auto() ) | |
stateMachine.MoveNext(); | |
} | |
public UniTask Task | |
{ | |
[DebuggerHidden] | |
get | |
{ | |
return new UniTask(this, core.Version); | |
} | |
} | |
[DebuggerHidden] | |
public void SetResult() | |
{ | |
core.TrySetResult(AsyncUnit.Default); | |
} | |
[DebuggerHidden] | |
public void SetException(Exception exception) | |
{ | |
core.TrySetException(exception); | |
} | |
[DebuggerHidden] | |
public void GetResult(short token) | |
{ | |
try | |
{ | |
core.GetResult(token); | |
} | |
finally | |
{ | |
#if ENABLE_IL2CPP | |
// workaround for IL2CPP bug. | |
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, returnDelegate); | |
#else | |
TryReturn(); | |
#endif | |
} | |
} | |
[DebuggerHidden] | |
public UniTaskStatus GetStatus(short token) | |
{ | |
return core.GetStatus(token); | |
} | |
[DebuggerHidden] | |
public UniTaskStatus UnsafeGetStatus() | |
{ | |
return core.UnsafeGetStatus(); | |
} | |
[DebuggerHidden] | |
public void OnCompleted(Action<object> continuation, object state, short token) | |
{ | |
core.OnCompleted(continuation, state, token); | |
} | |
ProfilerMarker profilerMarker; | |
} | |
internal sealed class AsyncUniTask<TStateMachine, T> : IStateMachineRunnerPromise<T>, IUniTaskSource<T>, ITaskPoolNode<AsyncUniTask<TStateMachine, T>> | |
where TStateMachine : IAsyncStateMachine | |
{ | |
static TaskPool<AsyncUniTask<TStateMachine, T>> pool; | |
#if ENABLE_IL2CPP | |
readonly Action returnDelegate; | |
#endif | |
public Action MoveNext { get; } | |
TStateMachine stateMachine; | |
UniTaskCompletionSourceCore<T> core; | |
ProfilerMarker profilerMarker; | |
AsyncUniTask() | |
{ | |
MoveNext = Run; | |
#if ENABLE_IL2CPP | |
returnDelegate = Return; | |
#endif | |
profilerMarker = new ProfilerMarker(typeof(TStateMachine).FullName); | |
} | |
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise<T> runnerPromiseFieldRef) | |
{ | |
if (!pool.TryPop(out var result)) | |
{ | |
result = new AsyncUniTask<TStateMachine, T>(); | |
} | |
TaskTracker.TrackActiveTask(result, 3); | |
runnerPromiseFieldRef = result; // set runner before copied. | |
result.stateMachine = stateMachine; // copy struct StateMachine(in release build). | |
} | |
AsyncUniTask<TStateMachine, T> nextNode; | |
public ref AsyncUniTask<TStateMachine, T> NextNode => ref nextNode; | |
static AsyncUniTask() | |
{ | |
TaskPool.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine, T>), () => pool.Size); | |
} | |
void Return() | |
{ | |
TaskTracker.RemoveTracking(this); | |
core.Reset(); | |
stateMachine = default; | |
pool.TryPush(this); | |
} | |
bool TryReturn() | |
{ | |
TaskTracker.RemoveTracking(this); | |
core.Reset(); | |
stateMachine = default; | |
return pool.TryPush(this); | |
} | |
[DebuggerHidden] | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
void Run() | |
{ | |
using (profilerMarker.Auto() ) | |
stateMachine.MoveNext(); | |
} | |
public UniTask<T> Task | |
{ | |
[DebuggerHidden] | |
get | |
{ | |
return new UniTask<T>(this, core.Version); | |
} | |
} | |
[DebuggerHidden] | |
public void SetResult(T result) | |
{ | |
core.TrySetResult(result); | |
} | |
[DebuggerHidden] | |
public void SetException(Exception exception) | |
{ | |
core.TrySetException(exception); | |
} | |
[DebuggerHidden] | |
public T GetResult(short token) | |
{ | |
try | |
{ | |
return core.GetResult(token); | |
} | |
finally | |
{ | |
#if ENABLE_IL2CPP | |
// workaround for IL2CPP bug. | |
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, returnDelegate); | |
#else | |
TryReturn(); | |
#endif | |
} | |
} | |
[DebuggerHidden] | |
void IUniTaskSource.GetResult(short token) | |
{ | |
GetResult(token); | |
} | |
[DebuggerHidden] | |
public UniTaskStatus GetStatus(short token) | |
{ | |
return core.GetStatus(token); | |
} | |
[DebuggerHidden] | |
public UniTaskStatus UnsafeGetStatus() | |
{ | |
return core.UnsafeGetStatus(); | |
} | |
[DebuggerHidden] | |
public void OnCompleted(Action<object> continuation, object state, short token) | |
{ | |
core.OnCompleted(continuation, state, token); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment