in Canvas/CanvasSimple/lib/winjs-4.0.1/js/base.js [4266:4447]
function run(scheduled) {
pumping = true;
schedulerProfilerMark("timeslice", "StartTM");
var didWork;
var ranJobSuccessfully = true;
var current;
var lastLoggedPriority;
var timesliceExhausted = false;
var yieldForPriorityBoundary = false;
// Reset per-run state
//
immediateYield = false;
try {
var start = now();
var end = start + TIME_SLICE;
// Yielding policy
//
// @TODO, should we have a different scheduler policy when the debugger is attached. Today if you
// break in user code we will generally yield immediately after that job due to the fact that any
// breakpoint will take longer than TIME_SLICE to process.
//
var shouldYield = function () {
timesliceExhausted = false;
if (immediateYield) { return true; }
if (wwaTaskScheduledAtPriorityHigherThan(toWwaPriority(highWaterMark))) { return true; }
if (!!drainQueue.length) { return false; }
if (now() > end) {
timesliceExhausted = true;
return true;
}
return false;
};
// Run until we run out of jobs or decide it is time to yield
//
while (highWaterMark >= Priority.min && !shouldYield() && !yieldForPriorityBoundary) {
didWork = false;
current = markerFromPriority(highWaterMark)._nextJob;
do {
// Record the priority currently being pumped
//
pumpingPriority = current.priority;
if (current instanceof JobNode) {
if (lastLoggedPriority !== current.priority) {
if (+lastLoggedPriority === lastLoggedPriority) {
schedulerProfilerMark("priority", "StopTM", markerFromPriority(lastLoggedPriority).name);
}
schedulerProfilerMark("priority", "StartTM", markerFromPriority(current.priority).name);
lastLoggedPriority = current.priority;
}
// Important that we update this state before calling execute because the
// job may throw an exception and we don't want to stall the queue.
//
didWork = true;
ranJobSuccessfully = false;
runningJob = current;
jobProfilerMark(runningJob, "job-running", "StartTM", markerFromPriority(pumpingPriority).name);
current._execute(shouldYield);
jobProfilerMark(runningJob, "job-running", "StopTM", markerFromPriority(pumpingPriority).name);
runningJob = null;
ranJobSuccessfully = true;
} else {
// As we pass marker nodes update our high water mark. It's important to do
// this before notifying drain listeners because they may schedule new jobs
// which will affect the highWaterMark.
//
var wwaPrevHighWaterMark = toWwaPriority(highWaterMark);
highWaterMark = current.priority;
didWork = notifyDrainListeners();
var wwaHighWaterMark = toWwaPriority(highWaterMark);
if (isHigherWwaPriority(wwaPrevHighWaterMark, wwaHighWaterMark) &&
(!usingWwaScheduler || MSApp.isTaskScheduledAtPriorityOrHigher(wwaHighWaterMark))) {
// Timeslice is moving to a lower WWA priority and the host
// has equally or more important work to do. Time to yield.
//
yieldForPriorityBoundary = true;
}
}
current = current._nextJob;
// When didWork is true we exit the loop because:
// - We've called into user code which may have modified the
// scheduler's queue. We need to restart at the high water mark.
// - We need to check if it's time for the scheduler to yield.
//
} while (current && !didWork && !yieldForPriorityBoundary && !wwaTaskScheduledAtPriorityHigherThan(toWwaPriority(highWaterMark)));
// Reset per-item state
//
immediateYield = false;
}
} finally {
runningJob = null;
// If a job was started and did not run to completion due to an exception
// we should transition it to a terminal state.
//
if (!ranJobSuccessfully) {
jobProfilerMark(current, "job-error", "info");
jobProfilerMark(current, "job-running", "StopTM", markerFromPriority(pumpingPriority).name);
current.cancel();
}
if (+lastLoggedPriority === lastLoggedPriority) {
schedulerProfilerMark("priority", "StopTM", markerFromPriority(lastLoggedPriority).name);
}
// Update high water mark to be the priority of the highest priority job.
//
var foundAJob = false;
while (highWaterMark >= Priority.min && !foundAJob) {
didWork = false;
current = markerFromPriority(highWaterMark)._nextJob;
do {
if (current instanceof JobNode) {
// We found a job. High water mark is now set to the priority
// of this job.
//
foundAJob = true;
} else {
// As we pass marker nodes update our high water mark. It's important to do
// this before notifying drain listeners because they may schedule new jobs
// which will affect the highWaterMark.
//
highWaterMark = current.priority;
didWork = notifyDrainListeners();
}
current = current._nextJob;
// When didWork is true we exit the loop because:
// - We've called into user code which may have modified the
// scheduler's queue. We need to restart at the high water mark.
//
} while (current && !didWork && !foundAJob);
}
var reasonForYielding;
if (!ranJobSuccessfully) {
reasonForYielding = "job error";
} else if (timesliceExhausted) {
reasonForYielding = "timeslice exhausted";
} else if (highWaterMark < Priority.min) {
reasonForYielding = "jobs exhausted";
} else if (yieldForPriorityBoundary) {
reasonForYielding = "reached WWA priority boundary";
} else {
reasonForYielding = "WWA host work";
}
// If this was a scheduled call to the pump, then the pump is no longer
// scheduled to be called and we should clear its scheduled priority.
//
if (scheduled) {
scheduledWwaPriority = null;
}
// If the high water mark has not reached the end of the queue then
// we re-queue in order to see if there are more jobs to run.
//
pumping = false;
if (highWaterMark >= Priority.min) {
startRunning();
}
schedulerProfilerMark("yielding", "info", reasonForYielding);
schedulerProfilerMark("timeslice", "StopTM");
}
}