private static void CheckPriorityQueue(PriorityNodeQueue<int> priorityQueue) { int lastItem = int.MinValue; while (!priorityQueue.Empty) { var value = priorityQueue.Dequeue(); Assert.That(value, Is.GreaterThanOrEqualTo(lastItem)); lastItem = value; } }
private static void CheckPriorityQueue(PriorityNodeQueue <int> priorityQueue) { int lastItem = int.MinValue; while (!priorityQueue.Empty) { var value = priorityQueue.Dequeue(); Assert.True(value >= lastItem); lastItem = value; } }
private static void CheckPriorityQueue(PriorityNodeQueue <int> priorityQueue) { int lastItem = int.MinValue; while (!priorityQueue.Empty) { var value = priorityQueue.Dequeue(); Assert.That(value, Is.GreaterThanOrEqualTo(lastItem)); lastItem = value; } }
private BuildStep GetNextBuildStep(int maxPriority) { while (true) { AssetBuildUnit unit; lock (queueLock) { if (queue.Empty) { return(null); } unit = queue.Dequeue(); } // Check that priority is good enough if (unit.PriorityMajor > maxPriority) { return(null); } var buildStep = unit.GetBuildStep(); // If this build step couldn't be built, let's find another one if (buildStep == null) { continue; } // Forward priority to build engine (still very coarse, but should help) buildStep.Priority = unit.PriorityMajor; foreach (var step in buildStep.EnumerateRecursively()) { var assetStep = step as AssetBuildStep; if (assetStep != null) { assetStep.Priority = unit.PriorityMajor; assetStep.StepProcessed += (s, e) => NotifyAssetBuilt(assetStep.AssetItem, assetStep.Logger); } } return(buildStep); } }
/// <summary> /// Runs until no runnable tasklets left. /// This function is reentrant. /// </summary> public void Run() { int managedThreadId = Thread.CurrentThread.ManagedThreadId; MicroThreadCallbackList callbacks = default(MicroThreadCallbackList); while (true) { SchedulerEntry schedulerEntry; MicroThread microThread; lock (ScheduledEntries) { // Reclaim callbacks of previous microthread MicroThreadCallbackNode callback; while (callbacks.TakeFirst(out callback)) { callback.Clear(); CallbackNodePool.Add(callback); } if (ScheduledEntries.Count == 0) { break; } schedulerEntry = ScheduledEntries.Dequeue(); microThread = schedulerEntry.MicroThread; if (microThread != null) { callbacks = microThread.Callbacks; microThread.Callbacks = default(MicroThreadCallbackList); } } // Since it can be reentrant, it should be restored after running the callback. var previousRunningMicrothread = runningMicroThread.Value; if (previousRunningMicrothread != null) { MicroThreadCallbackEnd?.Invoke(this, new SchedulerThreadEventArgs(previousRunningMicrothread, managedThreadId)); } runningMicroThread.Value = microThread; if (microThread != null) { var previousSyncContext = SynchronizationContext.Current; SynchronizationContext.SetSynchronizationContext(microThread.SynchronizationContext); // TODO: Do we still need to try/catch here? Everything should be caught in the continuation wrapper and put into MicroThread.Exception try { if (microThread.State == MicroThreadState.Starting) { MicroThreadStarted?.Invoke(this, new SchedulerThreadEventArgs(microThread, managedThreadId)); } MicroThreadCallbackStart?.Invoke(this, new SchedulerThreadEventArgs(microThread, managedThreadId)); var profilingKey = microThread.ProfilingKey ?? schedulerEntry.ProfilingKey ?? MicroThreadProfilingKeys.ProfilingKey; using (Profiler.Begin(profilingKey)) { var callback = callbacks.First; while (callback != null) { callback.Invoke(); callback = callback.Next; } } } catch (Exception e) { Log.Error("Unexpected exception while executing a micro-thread", e); microThread.SetException(e); } finally { MicroThreadCallbackEnd?.Invoke(this, new SchedulerThreadEventArgs(microThread, managedThreadId)); SynchronizationContext.SetSynchronizationContext(previousSyncContext); if (microThread.IsOver) { lock (microThread.AllLinkedListNode) { if (microThread.CompletionTask != null) { if (microThread.State == MicroThreadState.Failed || microThread.State == MicroThreadState.Canceled) { microThread.CompletionTask.TrySetException(microThread.Exception); } else { microThread.CompletionTask.TrySetResult(1); } } else if (microThread.State == MicroThreadState.Failed && microThread.Exception != null) { // Nothing was listening on the micro thread and it crashed // Let's treat it as unhandled exception and propagate it // Use ExceptionDispatchInfo.Capture to not overwrite callstack if (PropagateExceptions && (microThread.Flags & MicroThreadFlags.IgnoreExceptions) != MicroThreadFlags.IgnoreExceptions) { ExceptionDispatchInfo.Capture(microThread.Exception).Throw(); } } MicroThreadEnded?.Invoke(this, new SchedulerThreadEventArgs(microThread, managedThreadId)); } } runningMicroThread.Value = previousRunningMicrothread; if (previousRunningMicrothread != null) { MicroThreadCallbackStart?.Invoke(this, new SchedulerThreadEventArgs(previousRunningMicrothread, managedThreadId)); } } } else { try { var profilingKey = schedulerEntry.ProfilingKey ?? MicroThreadProfilingKeys.ProfilingKey; using (Profiler.Begin(profilingKey)) { schedulerEntry.Action(); } } catch (Exception e) { ActionException?.Invoke(this, schedulerEntry, e); } } } while (FrameChannel.Balance < 0) { FrameChannel.Send(0); } }
/// <summary> /// Runs until no runnable tasklets left. /// This function is reentrant. /// </summary> public void Run() { #if SILICONSTUDIO_PLATFORM_WINDOWS_RUNTIME int managedThreadId = 0; #else int managedThreadId = Thread.CurrentThread.ManagedThreadId; #endif while (true) { Action callback; MicroThread microThread; lock (scheduledMicroThreads) { if (scheduledMicroThreads.Count == 0) { break; } microThread = scheduledMicroThreads.Dequeue(); callback = microThread.Callback; microThread.Callback = null; } // Since it can be reentrant, it should be restored after running the callback. var previousRunningMicrothread = runningMicroThread.Value; if (previousRunningMicrothread != null) { if (MicroThreadCallbackEnd != null) { MicroThreadCallbackEnd(this, new SchedulerThreadEventArgs(previousRunningMicrothread, managedThreadId)); } } runningMicroThread.Value = microThread; var previousSyncContext = SynchronizationContext.Current; SynchronizationContext.SetSynchronizationContext(microThread.SynchronizationContext); try { if (microThread.State == MicroThreadState.Starting && MicroThreadStarted != null) { MicroThreadStarted(this, new SchedulerThreadEventArgs(microThread, managedThreadId)); } if (MicroThreadCallbackStart != null) { MicroThreadCallbackStart(this, new SchedulerThreadEventArgs(microThread, managedThreadId)); } using (Profiler.Begin(microThread.ProfilingKey)) { callback(); } } catch (Exception e) { Log.Error("Unexpected exception while executing a micro-thread", e); microThread.SetException(e); } finally { if (MicroThreadCallbackEnd != null) { MicroThreadCallbackEnd(this, new SchedulerThreadEventArgs(microThread, managedThreadId)); } SynchronizationContext.SetSynchronizationContext(previousSyncContext); if (microThread.IsOver) { lock (microThread.AllLinkedListNode) { if (microThread.CompletionTask != null) { if (microThread.State == MicroThreadState.Failed || microThread.State == MicroThreadState.Cancelled) { microThread.CompletionTask.TrySetException(microThread.Exception); } else { microThread.CompletionTask.TrySetResult(1); } } else if (microThread.State == MicroThreadState.Failed && microThread.Exception != null) { // Nothing was listening on the micro thread and it crashed // Let's treat it as unhandled exception and propagate it // Use ExceptionDispatchInfo.Capture to not overwrite callstack if ((microThread.Flags & MicroThreadFlags.IgnoreExceptions) != MicroThreadFlags.IgnoreExceptions) { ExceptionDispatchInfo.Capture(microThread.Exception).Throw(); } } if (MicroThreadEnded != null) { MicroThreadEnded(this, new SchedulerThreadEventArgs(microThread, managedThreadId)); } } } runningMicroThread.Value = previousRunningMicrothread; if (previousRunningMicrothread != null) { if (MicroThreadCallbackStart != null) { MicroThreadCallbackStart(this, new SchedulerThreadEventArgs(previousRunningMicrothread, managedThreadId)); } } } } while (FrameChannel.Balance < 0) { FrameChannel.Send(0); } }