unity/EditorPlugin/MainThreadDispatcher.cs (58 lines of code) (raw):
using System;
using System.Collections.Generic;
using System.Threading;
using JetBrains.Collections.Viewable;
using JetBrains.Diagnostics;
using UnityEditor;
namespace JetBrains.Rider.Unity.Editor
{
internal class MainThreadDispatcher : IScheduler
{
private static Thread ourUIThread;
internal static readonly MainThreadDispatcher Instance = new MainThreadDispatcher();
/// <summary>
/// The queue of tasks that are being requested for the next time DispatchTasks is called
/// </summary>
private readonly Queue<Action> myTaskQueue = new Queue<Action>();
private MainThreadDispatcher()
{
PluginEntryPoint.AppDomainLifetime.Bracket(() => EditorApplication.update += DispatchTasks,
() => EditorApplication.update -= DispatchTasks);
}
/// <summary>
/// Dispatches the specified action delegate.
/// </summary>
/// <param name="action">Action being requested</param>
public void Queue(Action action)
{
if (Thread.CurrentThread == ourUIThread)
{
action();
return;
}
lock (myTaskQueue)
{
myTaskQueue.Enqueue(action);
}
}
/// <summary>
/// Dispatches the tasks that has been requested since the last call to this function
/// </summary>
private void DispatchTasks()
{
ourUIThread = Thread.CurrentThread;
if (myTaskQueue.Count == 0)
return;
while (true)
{
try
{
if (myTaskQueue.Count == 0)
return;
var task = myTaskQueue.Dequeue();
task();
}
catch (Exception e)
{
Log.GetLog<MainThreadDispatcher>().Error(e);
}
}
}
public static void AssertThread()
{
Assertion.Require(ourUIThread == null || ourUIThread == Thread.CurrentThread, "Not a UI thread");
}
/// <summary>
/// Indicates whether there are tasks available for dispatching
/// </summary>
/// <value>
/// <c>true</c> if there are tasks available for dispatching; otherwise, <c>false</c>.
/// </value>
public bool IsActive => ourUIThread == null || ourUIThread == Thread.CurrentThread;
public bool OutOfOrderExecution => false;
}
}