/// <summary> /// Schedules work for this worker. /// </summary> internal void Schedule(AsyncWorkUnit inUnit) { #if SUPPORTS_THREADING lock (m_LockObject) { if ((inUnit.AsyncFlags & AsyncFlags.MainThreadOnly) != 0) { m_Scheduler.Log("Scheduling {0} on main thread", inUnit); m_MainThreadOnlyQueue.Enqueue(inUnit); } else { m_Scheduler.Log("Scheduling {0} in background", inUnit); m_BackgroundQueue.Enqueue(inUnit); } } #else if ((inUnit.AsyncFlags & AsyncFlags.MainThreadOnly) != 0) { m_Scheduler.Log("Scheduling {0} on main thread", inUnit); m_MainThreadOnlyQueue.Enqueue(inUnit); } else { m_Scheduler.Log("Scheduling {0} in background", inUnit); m_BackgroundQueue.Enqueue(inUnit); } #endif // SUPPORTS_THREADING }
// Loop to run on thread private void ProcessBackgroundQueueOnThread() { while (!ForceSingleThreaded) { if (Paused) { Thread.Sleep(PausedSleepMS); continue; } AsyncWorkUnit unit = null; lock (m_LockObject) { if (m_BackgroundQueue.Count > 0) { unit = m_BackgroundQueue.Peek(); } } if (unit == null) { Thread.Sleep(StarvationSleepMS); continue; } AsyncWorkUnit.StepResult result = AsyncWorkUnit.StepResult.Incomplete; while (result.IsIncomplete() && !ForceSingleThreaded && !Paused) { result = unit.ThreadedStep(); if (result.TickDelay > 0) { Thread.Sleep(TimeSpan.FromTicks(result.TickDelay)); } } if (!result.IsIncomplete()) { if (result.Type == AsyncWorkUnit.StepResultType.Complete) { m_Scheduler.Log("Completed {0}", unit); } lock (m_LockObject) { m_BackgroundQueue.Dequeue(); } m_Scheduler.FreeUnit(unit); } } lock (m_LockObject) { m_Thread = null; } }
// Allocates a work unit for the given enumerator. private AsyncWorkUnit AllocUnit(IEnumerator inEnumerator, AsyncFlags inFlags) { AsyncWorkUnit unit = AllocUnitImpl(); #if DEVELOPMENT string name = Fiber.GetTypeName(inEnumerator.GetType()); #else string name = "[not used]"; #endif // DEVELOPMENT unit.Initialize(null, inEnumerator, inFlags, name); return(unit); }
// Allocates a work unit for the given action. private AsyncWorkUnit AllocUnit(Action inAction, AsyncFlags inFlags) { AsyncWorkUnit unit = AllocUnitImpl(); #if DEVELOPMENT string name = string.Format("{0}->{1}::{2}", inAction.Target, inAction.Method.DeclaringType.FullName, inAction.Method.Name); #else string name = "[not used]"; #endif // DEVELOPMENT unit.Initialize(inAction, null, inFlags, name); return(unit); }
/// <summary> /// Schedules an enumerated action. /// </summary> internal AsyncHandle Schedule(IEnumerator inEnumerator, AsyncFlags inFlags) { if (inEnumerator == null) { return(AsyncHandle.Null); } AsyncWorkUnit unit = AllocUnit(inEnumerator, inFlags); ScheduleImpl(unit); return(unit.GetHandle()); }
/// <summary> /// Schedules an action. /// </summary> internal AsyncHandle Schedule(Action inAction, AsyncFlags inFlags) { if (inAction == null) { return(AsyncHandle.Null); } AsyncWorkUnit unit = AllocUnit(inAction, inFlags); ScheduleImpl(unit); return(unit.GetHandle()); }
/// <summary> /// Frees a work unit and returns it to the pool. /// </summary> internal void FreeUnit(AsyncWorkUnit inWorkUnit, bool inbDispatchCallbacks = true) { if (inbDispatchCallbacks) { inWorkUnit.DispatchStop(Dispatcher); } inWorkUnit.Clear(); #if SUPPORTS_THREADING lock (m_PoolLock) { m_WorkUnitPool.Add(inWorkUnit); } #else m_WorkUnitPool.Add(inWorkUnit); #endif // SUPPORTS_THREADING }
// Allocates a work unit from the pool. private AsyncWorkUnit AllocUnitImpl() { #if SUPPORTS_THREADING lock (m_PoolLock) { #endif // SUPPORTS_THREADING int idx = m_WorkUnitPool.Count - 1; if (idx < 0) { return(new AsyncWorkUnit(this)); } AsyncWorkUnit unit = m_WorkUnitPool[idx]; m_WorkUnitPool.RemoveAt(idx); return(unit); #if SUPPORTS_THREADING } #endif // SUPPORTS_THREADING }
// Processes scheduled work by time-slicing. private void ProcessBlockingQueue(Stopwatch inStopwatch, long inTotalBudget, long inSliceBudget, Queue <AsyncWorkUnit> ioQueue, bool inbCheckThread, ref long ioTicksRemaining) { #if SUPPORTS_THREADING if (inbCheckThread) { // if we have a running thread, don't process this frame lock (m_LockObject) { if (m_Thread != null) { ioTicksRemaining = inTotalBudget - inStopwatch.ElapsedTicks; return; } } } #endif // SUPPORTS_THREADING if (m_NextBlockingTick > 0) { long current = Stopwatch.GetTimestamp(); if (current < m_NextBlockingTick) { ioTicksRemaining = inTotalBudget - inStopwatch.ElapsedTicks; return; } m_NextBlockingTick = 0; } long timestamp = inStopwatch.ElapsedTicks; long cutoff = timestamp + inSliceBudget; while (!Paused && ioTicksRemaining > 0 && ioQueue.Count > 0 && timestamp < cutoff && m_NextBlockingTick <= 0) { AsyncWorkUnit unit = ioQueue.Peek(); AsyncWorkUnit.StepResult result = AsyncWorkUnit.StepResult.Incomplete; while (result.IsIncomplete() && ioTicksRemaining > 0 && !Paused && timestamp < cutoff && m_NextBlockingTick <= 0) { result = unit.Step(); if (result.TickDelay > 0) { m_NextBlockingTick = Stopwatch.GetTimestamp() + result.TickDelay; } timestamp = inStopwatch.ElapsedTicks; ioTicksRemaining = inTotalBudget - timestamp; } if (!result.IsIncomplete()) { if (result.Type == AsyncWorkUnit.StepResultType.Complete) { m_Scheduler.Log("Completed {0}", unit); } ioQueue.Dequeue(); m_Scheduler.FreeUnit(unit); timestamp = inStopwatch.ElapsedTicks; ioTicksRemaining = inTotalBudget - timestamp; } } }
// Schedules work to the given priority worker. private void ScheduleImpl(AsyncWorkUnit inUnit) { AsyncWorker worker = GetWorker(inUnit.AsyncFlags); worker.Schedule(inUnit); }