From b833ef8d249f43986f0738277bbde505aeee0d1c Mon Sep 17 00:00:00 2001 From: "Michael \"Z\" Goddard" Date: Fri, 19 Oct 2018 16:43:36 -0400 Subject: [PATCH] remove finished threads every loop of all threads When all threads are looped, finished threads must be removed so threads that are waiting for those to complete and be removed may continue executing. This effects broadcast and wait for example. The threads created by broadcast and wait can finish in the same tick and must be removed from the list of threads so that broadcast and wait knows to stop waiting. --- src/engine/sequencer.js | 50 ++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js index 7d40dd85a..5b3fcf005 100644 --- a/src/engine/sequencer.js +++ b/src/engine/sequencer.js @@ -74,7 +74,7 @@ class Sequencer { let numActiveThreads = Infinity; // Whether `stepThreads` has run through a full single tick. let ranFirstTick = false; - const doneThreads = this.runtime.threads.map(() => null); + const doneThreads = []; // Conditions for continuing to stepping threads: // 1. We must have threads in the list, and some must be active. // 2. Time elapsed must be less than WORK_TIME. @@ -91,19 +91,17 @@ class Sequencer { } numActiveThreads = 0; + let stoppedThread = false; // Attempt to run each thread one time. for (let i = 0; i < this.runtime.threads.length; i++) { const activeThread = this.runtime.threads[i]; + // Check if the thread is done so it is not executed. if (activeThread.stack.length === 0 || activeThread.status === Thread.STATUS_DONE) { // Finished with this thread. - doneThreads[i] = activeThread; + stoppedThread = true; continue; } - // A thread was removed, added or this thread was restarted. - if (doneThreads[i] !== null) { - doneThreads[i] = null; - } if (activeThread.status === Thread.STATUS_YIELD_TICK && !ranFirstTick) { // Clear single-tick yield from the last call of `stepThreads`. @@ -130,6 +128,13 @@ class Sequencer { if (activeThread.status === Thread.STATUS_RUNNING) { numActiveThreads++; } + // Check if the thread completed while it just stepped to make + // sure we remove it before the next iteration of all threads. + if (activeThread.stack.length === 0 || + activeThread.status === Thread.STATUS_DONE) { + // Finished with this thread. + stoppedThread = true; + } } // We successfully ticked once. Prevents running STATUS_YIELD_TICK // threads on the next tick. @@ -138,28 +143,23 @@ class Sequencer { if (this.runtime.profiler !== null) { this.runtime.profiler.stop(); } - } - // Filter inactive threads from `this.runtime.threads`. - numActiveThreads = 0; - for (let i = 0; i < this.runtime.threads.length; i++) { - const thread = this.runtime.threads[i]; - if (doneThreads[i] === null) { - this.runtime.threads[numActiveThreads] = thread; - numActiveThreads++; - } - } - this.runtime.threads.length = numActiveThreads; - // Filter undefined and null values from `doneThreads`. - let numDoneThreads = 0; - for (let i = 0; i < doneThreads.length; i++) { - const maybeThread = doneThreads[i]; - if (maybeThread !== null) { - doneThreads[numDoneThreads] = maybeThread; - numDoneThreads++; + // Filter inactive threads from `this.runtime.threads`. + if (stoppedThread) { + let nextActiveThread = 0; + for (let i = 0; i < this.runtime.threads.length; i++) { + const thread = this.runtime.threads[i]; + if (thread.stack.length !== 0 && + thread.status !== Thread.STATUS_DONE) { + this.runtime.threads[nextActiveThread] = thread; + nextActiveThread++; + } else { + doneThreads.push(thread); + } + } + this.runtime.threads.length = nextActiveThread; } } - doneThreads.length = numDoneThreads; return doneThreads; }