// this code is borrowed from RxOfficial(rx.codeplex.com) and modified // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System.ComponentModel; using System.Threading; using UniRx.InternalUtil; using UniRx; using System; using System.Diagnostics; using System.Collections.Generic; namespace UniRx { public static partial class Scheduler { public static readonly IScheduler CurrentThread = new CurrentThreadScheduler(); public static bool IsCurrentThreadSchedulerScheduleRequired { get { return CurrentThreadScheduler.IsScheduleRequired; } } /// /// Represents an object that schedules units of work on the current thread. /// /// Singleton instance of this type exposed through this static property. class CurrentThreadScheduler : IScheduler { [ThreadStatic] static SchedulerQueue s_threadLocalQueue; [ThreadStatic] static Stopwatch s_clock; private static SchedulerQueue GetQueue() { return s_threadLocalQueue; } private static void SetQueue(SchedulerQueue newQueue) { s_threadLocalQueue = newQueue; } private static TimeSpan Time { get { if (s_clock == null) s_clock = Stopwatch.StartNew(); return s_clock.Elapsed; } } /// /// Gets a value that indicates whether the caller must call a Schedule method. /// [EditorBrowsable(EditorBrowsableState.Advanced)] public static bool IsScheduleRequired { get { return GetQueue() == null; } } public IDisposable Schedule(Action action) { return Schedule(TimeSpan.Zero, action); } public IDisposable Schedule(TimeSpan dueTime, Action action) { if (action == null) throw new ArgumentNullException("action"); var dt = Time + Scheduler.Normalize(dueTime); var si = new ScheduledItem(action, dt); var queue = GetQueue(); if (queue == null) { queue = new SchedulerQueue(4); queue.Enqueue(si); CurrentThreadScheduler.SetQueue(queue); try { Trampoline.Run(queue); } finally { CurrentThreadScheduler.SetQueue(null); } } else { queue.Enqueue(si); } return si.Cancellation; } static class Trampoline { public static void Run(SchedulerQueue queue) { while (queue.Count > 0) { var item = queue.Dequeue(); if (!item.IsCanceled) { var wait = item.DueTime - CurrentThreadScheduler.Time; if (wait.Ticks > 0) { Thread.Sleep(wait); } if (!item.IsCanceled) item.Invoke(); } } } } public DateTimeOffset Now { get { return Scheduler.Now; } } } } }