|
|
|
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
|
|
|
|
|
namespace Cysharp.Threading.Tasks.Internal
|
|
|
|
|
{
|
|
|
|
|
internal sealed class ContinuationQueue
|
|
|
|
|
{
|
|
|
|
|
const int MaxArrayLength = 0X7FEFFFFF;
|
|
|
|
|
const int InitialSize = 16;
|
|
|
|
|
|
|
|
|
|
readonly PlayerLoopTiming timing;
|
|
|
|
|
|
|
|
|
|
SpinLock gate = new SpinLock(false);
|
|
|
|
|
bool dequing = false;
|
|
|
|
|
|
|
|
|
|
int actionListCount = 0;
|
|
|
|
|
Action[] actionList = new Action[InitialSize];
|
|
|
|
|
|
|
|
|
|
int waitingListCount = 0;
|
|
|
|
|
Action[] waitingList = new Action[InitialSize];
|
|
|
|
|
|
|
|
|
|
public ContinuationQueue(PlayerLoopTiming timing)
|
|
|
|
|
{
|
|
|
|
|
this.timing = timing;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Enqueue(Action continuation)
|
|
|
|
|
{
|
|
|
|
|
bool lockTaken = false;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
gate.Enter(ref lockTaken);
|
|
|
|
|
|
|
|
|
|
if (dequing)
|
|
|
|
|
{
|
|
|
|
|
// Ensure Capacity
|
|
|
|
|
if (waitingList.Length == waitingListCount)
|
|
|
|
|
{
|
|
|
|
|
var newLength = waitingListCount * 2;
|
|
|
|
|
if ((uint)newLength > MaxArrayLength) newLength = MaxArrayLength;
|
|
|
|
|
|
|
|
|
|
var newArray = new Action[newLength];
|
|
|
|
|
Array.Copy(waitingList, newArray, waitingListCount);
|
|
|
|
|
waitingList = newArray;
|
|
|
|
|
}
|
|
|
|
|
waitingList[waitingListCount] = continuation;
|
|
|
|
|
waitingListCount++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Ensure Capacity
|
|
|
|
|
if (actionList.Length == actionListCount)
|
|
|
|
|
{
|
|
|
|
|
var newLength = actionListCount * 2;
|
|
|
|
|
if ((uint)newLength > MaxArrayLength) newLength = MaxArrayLength;
|
|
|
|
|
|
|
|
|
|
var newArray = new Action[newLength];
|
|
|
|
|
Array.Copy(actionList, newArray, actionListCount);
|
|
|
|
|
actionList = newArray;
|
|
|
|
|
}
|
|
|
|
|
actionList[actionListCount] = continuation;
|
|
|
|
|
actionListCount++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
if (lockTaken) gate.Exit(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int Clear()
|
|
|
|
|
{
|
|
|
|
|
var rest = actionListCount + waitingListCount;
|
|
|
|
|
|
|
|
|
|
actionListCount = 0;
|
|
|
|
|
actionList = new Action[InitialSize];
|
|
|
|
|
|
|
|
|
|
waitingListCount = 0;
|
|
|
|
|
waitingList = new Action[InitialSize];
|
|
|
|
|
|
|
|
|
|
return rest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// delegate entrypoint.
|
|
|
|
|
public void Run()
|
|
|
|
|
{
|
|
|
|
|
// for debugging, create named stacktrace.
|
|
|
|
|
#if DEBUG
|
|
|
|
|
switch (timing)
|
|
|
|
|
{
|
|
|
|
|
case PlayerLoopTiming.Initialization:
|
|
|
|
|
Initialization();
|
|
|
|
|
break;
|
|
|
|
|
case PlayerLoopTiming.LastInitialization:
|
|
|
|
|
LastInitialization();
|
|
|
|
|
break;
|
|
|
|
|
case PlayerLoopTiming.EarlyUpdate:
|
|
|
|
|
EarlyUpdate();
|
|
|
|
|
break;
|
|
|
|
|
case PlayerLoopTiming.LastEarlyUpdate:
|
|
|
|
|
LastEarlyUpdate();
|
|
|
|
|
break;
|
|
|
|
|
case PlayerLoopTiming.FixedUpdate:
|
|
|
|
|
FixedUpdate();
|
|
|
|
|
break;
|
|
|
|
|
case PlayerLoopTiming.LastFixedUpdate:
|
|
|
|
|
LastFixedUpdate();
|
|
|
|
|
break;
|
|
|
|
|
case PlayerLoopTiming.PreUpdate:
|
|
|
|
|
PreUpdate();
|
|
|
|
|
break;
|
|
|
|
|
case PlayerLoopTiming.LastPreUpdate:
|
|
|
|
|
LastPreUpdate();
|
|
|
|
|
break;
|
|
|
|
|
case PlayerLoopTiming.Update:
|
|
|
|
|
Update();
|
|
|
|
|
break;
|
|
|
|
|
case PlayerLoopTiming.LastUpdate:
|
|
|
|
|
LastUpdate();
|
|
|
|
|
break;
|
|
|
|
|
case PlayerLoopTiming.PreLateUpdate:
|
|
|
|
|
PreLateUpdate();
|
|
|
|
|
break;
|
|
|
|
|
case PlayerLoopTiming.LastPreLateUpdate:
|
|
|
|
|
LastPreLateUpdate();
|
|
|
|
|
break;
|
|
|
|
|
case PlayerLoopTiming.PostLateUpdate:
|
|
|
|
|
PostLateUpdate();
|
|
|
|
|
break;
|
|
|
|
|
case PlayerLoopTiming.LastPostLateUpdate:
|
|
|
|
|
LastPostLateUpdate();
|
|
|
|
|
break;
|
|
|
|
|
#if UNITY_2020_2_OR_NEWER
|
|
|
|
|
case PlayerLoopTiming.TimeUpdate:
|
|
|
|
|
TimeUpdate();
|
|
|
|
|
break;
|
|
|
|
|
case PlayerLoopTiming.LastTimeUpdate:
|
|
|
|
|
LastTimeUpdate();
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
RunCore();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Initialization() => RunCore();
|
|
|
|
|
void LastInitialization() => RunCore();
|
|
|
|
|
void EarlyUpdate() => RunCore();
|
|
|
|
|
void LastEarlyUpdate() => RunCore();
|
|
|
|
|
void FixedUpdate() => RunCore();
|
|
|
|
|
void LastFixedUpdate() => RunCore();
|
|
|
|
|
void PreUpdate() => RunCore();
|
|
|
|
|
void LastPreUpdate() => RunCore();
|
|
|
|
|
void Update() => RunCore();
|
|
|
|
|
void LastUpdate() => RunCore();
|
|
|
|
|
void PreLateUpdate() => RunCore();
|
|
|
|
|
void LastPreLateUpdate() => RunCore();
|
|
|
|
|
void PostLateUpdate() => RunCore();
|
|
|
|
|
void LastPostLateUpdate() => RunCore();
|
|
|
|
|
#if UNITY_2020_2_OR_NEWER
|
|
|
|
|
void TimeUpdate() => RunCore();
|
|
|
|
|
void LastTimeUpdate() => RunCore();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
[System.Diagnostics.DebuggerHidden]
|
|
|
|
|
void RunCore()
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
bool lockTaken = false;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
gate.Enter(ref lockTaken);
|
|
|
|
|
if (actionListCount == 0) return;
|
|
|
|
|
dequing = true;
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
if (lockTaken) gate.Exit(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < actionListCount; i++)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
var action = actionList[i];
|
|
|
|
|
actionList[i] = null;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
action();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
UnityEngine.Debug.LogException(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
bool lockTaken = false;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
gate.Enter(ref lockTaken);
|
|
|
|
|
dequing = false;
|
|
|
|
|
|
|
|
|
|
var swapTempActionList = actionList;
|
|
|
|
|
|
|
|
|
|
actionListCount = waitingListCount;
|
|
|
|
|
actionList = waitingList;
|
|
|
|
|
|
|
|
|
|
waitingListCount = 0;
|
|
|
|
|
waitingList = swapTempActionList;
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
if (lockTaken) gate.Exit(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|