You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
4.5 KiB
158 lines
4.5 KiB
using System; |
|
using System.Runtime.InteropServices; |
|
using System.Threading; |
|
|
|
namespace Cysharp.Threading.Tasks |
|
{ |
|
public class UniTaskSynchronizationContext : SynchronizationContext |
|
{ |
|
const int MaxArrayLength = 0X7FEFFFFF; |
|
const int InitialSize = 16; |
|
|
|
static SpinLock gate = new SpinLock(false); |
|
static bool dequing = false; |
|
|
|
static int actionListCount = 0; |
|
static Callback[] actionList = new Callback[InitialSize]; |
|
|
|
static int waitingListCount = 0; |
|
static Callback[] waitingList = new Callback[InitialSize]; |
|
|
|
static int opCount; |
|
|
|
public override void Send(SendOrPostCallback d, object state) |
|
{ |
|
d(state); |
|
} |
|
|
|
public override void Post(SendOrPostCallback d, object state) |
|
{ |
|
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 Callback[newLength]; |
|
Array.Copy(waitingList, newArray, waitingListCount); |
|
waitingList = newArray; |
|
} |
|
waitingList[waitingListCount] = new Callback(d, state); |
|
waitingListCount++; |
|
} |
|
else |
|
{ |
|
// Ensure Capacity |
|
if (actionList.Length == actionListCount) |
|
{ |
|
var newLength = actionListCount * 2; |
|
if ((uint)newLength > MaxArrayLength) newLength = MaxArrayLength; |
|
|
|
var newArray = new Callback[newLength]; |
|
Array.Copy(actionList, newArray, actionListCount); |
|
actionList = newArray; |
|
} |
|
actionList[actionListCount] = new Callback(d, state); |
|
actionListCount++; |
|
} |
|
} |
|
finally |
|
{ |
|
if (lockTaken) gate.Exit(false); |
|
} |
|
} |
|
|
|
public override void OperationStarted() |
|
{ |
|
Interlocked.Increment(ref opCount); |
|
} |
|
|
|
public override void OperationCompleted() |
|
{ |
|
Interlocked.Decrement(ref opCount); |
|
} |
|
|
|
public override SynchronizationContext CreateCopy() |
|
{ |
|
return this; |
|
} |
|
|
|
// delegate entrypoint. |
|
internal static void Run() |
|
{ |
|
{ |
|
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] = default; |
|
action.Invoke(); |
|
} |
|
|
|
{ |
|
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); |
|
} |
|
} |
|
} |
|
|
|
[StructLayout(LayoutKind.Auto)] |
|
readonly struct Callback |
|
{ |
|
readonly SendOrPostCallback callback; |
|
readonly object state; |
|
|
|
public Callback(SendOrPostCallback callback, object state) |
|
{ |
|
this.callback = callback; |
|
this.state = state; |
|
} |
|
|
|
public void Invoke() |
|
{ |
|
try |
|
{ |
|
callback(state); |
|
} |
|
catch (Exception ex) |
|
{ |
|
UnityEngine.Debug.LogException(ex); |
|
} |
|
} |
|
} |
|
} |
|
} |