diff --git a/src/engine/execute.js b/src/engine/execute.js index 0d1dbc3cc..6c58cd156 100644 --- a/src/engine/execute.js +++ b/src/engine/execute.js @@ -1,5 +1,3 @@ -var YieldTimers = require('../util/yieldtimers.js'); - /** * If set, block calls, args, and return values will be logged to the console. * @const {boolean} @@ -13,11 +11,6 @@ var execute = function (sequencer, thread) { var currentBlockId = thread.peekStack(); var currentStackFrame = thread.peekStackFrame(); - // Save the yield timer ID, in case a primitive makes a new one - // @todo hack - perhaps patch this to allow more than one timer per - // primitive, for example... - var oldYieldTimerId = YieldTimers.timerId; - var opcode = runtime.blocks.getOpcode(currentBlockId); // Generate values for arguments (inputs). @@ -64,17 +57,12 @@ var execute = function (sequencer, thread) { done: function() { sequencer.proceedThread(thread); }, - timeout: YieldTimers.timeout, + timeout: thread.addTimeout.bind(thread), stackFrame: currentStackFrame, startSubstack: function (substackNum) { sequencer.stepToSubstack(thread, substackNum); } }); - // Update if the thread has set a yield timer ID - // @todo hack - if (YieldTimers.timerId > oldYieldTimerId) { - thread.yieldTimerId = YieldTimers.timerId; - } if (DEBUG_BLOCK_CALLS) { console.log('ending stack frame: ', currentStackFrame); console.log('returned: ', primitiveReturnValue); diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js index deaa15266..1541d1c6f 100644 --- a/src/engine/sequencer.js +++ b/src/engine/sequencer.js @@ -53,10 +53,10 @@ Sequencer.prototype.stepThreads = function (threads) { // Normal-mode thread: step. this.startThread(activeThread); } else if (activeThread.status === Thread.STATUS_YIELD) { - // Yield-mode thread: check if the time has passed. - if (!YieldTimers.resolve(activeThread.yieldTimerId)) { - // Thread is still yielding - // if YieldTimers.resolve returns false. + // Yield-mode thread: resolve timers. + activeThread.resolveTimeouts(); + if (activeThread.status === Thread.STATUS_YIELD) { + // Still yielding. numYieldingThreads++; } } else if (activeThread.status === Thread.STATUS_DONE) { diff --git a/src/engine/thread.js b/src/engine/thread.js index c98efab48..bd991db27 100644 --- a/src/engine/thread.js +++ b/src/engine/thread.js @@ -1,3 +1,5 @@ +var YieldTimers = require('../util/yieldtimers.js'); + /** * A thread is a running stack context and all the metadata needed. * @param {?string} firstBlock First block to execute in the thread. @@ -30,10 +32,10 @@ function Thread (firstBlock) { this.status = 0; /* Thread.STATUS_RUNNING */ /** - * Yield timer ID (for checking when the thread should unyield). + * Execution-synced timeouts. * @type {number} */ - this.yieldTimerId = -1; + this.timeoutIds = []; } /** @@ -104,4 +106,29 @@ Thread.prototype.yield = function () { this.status = Thread.STATUS_YIELD; }; +/** + * Add an execution-synced timeouts for this thread. + * See also: util/yieldtimers.js:timeout + * @param {!Function} callback To be called when the timer is done. + * @param {number} timeDelta Time to wait, in ms. + */ +Thread.prototype.addTimeout = function (callback, timeDelta) { + var timeoutId = YieldTimers.timeout(callback, timeDelta); + this.timeoutIds.push(timeoutId); +}; + +/** + * Attempt to resolve all execution-synced timeouts on this thread. + */ +Thread.prototype.resolveTimeouts = function () { + var newTimeouts = []; + for (var i = 0; i < this.timeoutIds.length; i++) { + var resolved = YieldTimers.resolve(this.timeoutIds[i]); + if (!resolved) { + newTimeouts.push(this.timeoutIds[i]); + } + } + this.timeoutIds = newTimeouts; +}; + module.exports = Thread; diff --git a/src/util/yieldtimers.js b/src/util/yieldtimers.js index 45e244eaf..84c6d3259 100644 --- a/src/util/yieldtimers.js +++ b/src/util/yieldtimers.js @@ -68,23 +68,4 @@ YieldTimers.resolve = function (id) { return true; }; -/** - * Reject a timer so the callback never executes. - * @param {number} id Timer ID to reject. - */ -YieldTimers.reject = function (id) { - if (YieldTimers.timers[id]) { - delete YieldTimers.timers[id]; - } -}; - -/** - * Reject all timers currently stored. - * Especially useful for a Scratch "stop." - */ -YieldTimers.rejectAll = function () { - YieldTimers.timers = {}; - YieldTimers.timerId = 0; -}; - module.exports = YieldTimers;