1a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Copyright 2006-2008 the V8 project authors. All rights reserved. 2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Redistribution and use in source and binary forms, with or without 3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// modification, are permitted provided that the following conditions are 4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// met: 5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Redistributions of source code must retain the above copyright 7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// notice, this list of conditions and the following disclaimer. 8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Redistributions in binary form must reproduce the above 9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// copyright notice, this list of conditions and the following 10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// disclaimer in the documentation and/or other materials provided 11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// with the distribution. 12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Neither the name of Google Inc. nor the names of its 13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// contributors may be used to endorse or promote products derived 14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// from this software without specific prior written permission. 15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// This is a JavaScript implementation of the Richards 30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// benchmark from: 31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// http://www.cl.cam.ac.uk/~mr10/Bench.html 33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// The benchmark was originally implemented in BCPL by 35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Martin Richards. 36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 380d5e116f6aee03185f237311a943491bb079a768Kristian Monsenvar Richards = new BenchmarkSuite('Richards', 35302, [ 39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block new Benchmark("Richards", runRichards) 40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block]); 41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * The Richards benchmark simulates the task dispatcher of an 45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * operating system. 46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block **/ 47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction runRichards() { 48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var scheduler = new Scheduler(); 49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block scheduler.addIdleTask(ID_IDLE, 0, null, COUNT); 50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var queue = new Packet(null, ID_WORKER, KIND_WORK); 52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block queue = new Packet(queue, ID_WORKER, KIND_WORK); 53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block scheduler.addWorkerTask(ID_WORKER, 1000, queue); 54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block queue = new Packet(null, ID_DEVICE_A, KIND_DEVICE); 56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block queue = new Packet(queue, ID_DEVICE_A, KIND_DEVICE); 57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block queue = new Packet(queue, ID_DEVICE_A, KIND_DEVICE); 58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block scheduler.addHandlerTask(ID_HANDLER_A, 2000, queue); 59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block queue = new Packet(null, ID_DEVICE_B, KIND_DEVICE); 61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block queue = new Packet(queue, ID_DEVICE_B, KIND_DEVICE); 62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block queue = new Packet(queue, ID_DEVICE_B, KIND_DEVICE); 63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block scheduler.addHandlerTask(ID_HANDLER_B, 3000, queue); 64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block scheduler.addDeviceTask(ID_DEVICE_A, 4000, null); 66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block scheduler.addDeviceTask(ID_DEVICE_B, 5000, null); 68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block scheduler.schedule(); 70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (scheduler.queueCount != EXPECTED_QUEUE_COUNT || 72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block scheduler.holdCount != EXPECTED_HOLD_COUNT) { 73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var msg = 74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "Error during execution: queueCount = " + scheduler.queueCount + 75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ", holdCount = " + scheduler.holdCount + "."; 76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block throw new Error(msg); 77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar COUNT = 1000; 81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * These two constants specify how many times a packet is queued and 84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * how many times a task is put on hold in a correct run of richards. 85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * They don't have any meaning a such but are characteristic of a 86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * correct run so if the actual queue or hold count is different from 87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * the expected there must be a bug in the implementation. 88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block **/ 89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar EXPECTED_QUEUE_COUNT = 2322; 90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar EXPECTED_HOLD_COUNT = 928; 91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * A scheduler can be used to schedule a set of tasks based on their relative 95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * priorities. Scheduling is done by maintaining a list of task control blocks 96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * which holds tasks and the data queue they are processing. 97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @constructor 98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction Scheduler() { 100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.queueCount = 0; 101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.holdCount = 0; 102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.blocks = new Array(NUMBER_OF_IDS); 103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.list = null; 104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.currentTcb = null; 105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.currentId = null; 106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar ID_IDLE = 0; 109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar ID_WORKER = 1; 110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar ID_HANDLER_A = 2; 111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar ID_HANDLER_B = 3; 112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar ID_DEVICE_A = 4; 113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar ID_DEVICE_B = 5; 114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar NUMBER_OF_IDS = 6; 115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar KIND_DEVICE = 0; 117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar KIND_WORK = 1; 118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * Add an idle task to this scheduler. 121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} id the identity of the task 122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} priority the task's priority 123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {Packet} queue the queue of work to be processed by the task 124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} count the number of times to schedule the task 125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockScheduler.prototype.addIdleTask = function (id, priority, queue, count) { 127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.addRunningTask(id, priority, queue, new IdleTask(this, 1, count)); 128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * Add a work task to this scheduler. 132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} id the identity of the task 133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} priority the task's priority 134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {Packet} queue the queue of work to be processed by the task 135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockScheduler.prototype.addWorkerTask = function (id, priority, queue) { 137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.addTask(id, priority, queue, new WorkerTask(this, ID_HANDLER_A, 0)); 138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * Add a handler task to this scheduler. 142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} id the identity of the task 143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} priority the task's priority 144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {Packet} queue the queue of work to be processed by the task 145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockScheduler.prototype.addHandlerTask = function (id, priority, queue) { 147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.addTask(id, priority, queue, new HandlerTask(this)); 148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * Add a handler task to this scheduler. 152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} id the identity of the task 153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} priority the task's priority 154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {Packet} queue the queue of work to be processed by the task 155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockScheduler.prototype.addDeviceTask = function (id, priority, queue) { 157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.addTask(id, priority, queue, new DeviceTask(this)) 158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * Add the specified task and mark it as running. 162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} id the identity of the task 163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} priority the task's priority 164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {Packet} queue the queue of work to be processed by the task 165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {Task} task the task to add 166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockScheduler.prototype.addRunningTask = function (id, priority, queue, task) { 168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.addTask(id, priority, queue, task); 169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.currentTcb.setRunning(); 170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * Add the specified task to this scheduler. 174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} id the identity of the task 175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} priority the task's priority 176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {Packet} queue the queue of work to be processed by the task 177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {Task} task the task to add 178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockScheduler.prototype.addTask = function (id, priority, queue, task) { 180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.currentTcb = new TaskControlBlock(this.list, id, priority, queue, task); 181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.list = this.currentTcb; 182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.blocks[id] = this.currentTcb; 183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * Execute the tasks managed by this scheduler. 187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockScheduler.prototype.schedule = function () { 189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.currentTcb = this.list; 190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (this.currentTcb != null) { 191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (this.currentTcb.isHeldOrSuspended()) { 192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.currentTcb = this.currentTcb.link; 193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.currentId = this.currentTcb.id; 195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.currentTcb = this.currentTcb.run(); 196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * Release a task that is currently blocked and return the next block to run. 202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} id the id of the task to suspend 203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockScheduler.prototype.release = function (id) { 205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var tcb = this.blocks[id]; 206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (tcb == null) return tcb; 207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block tcb.markAsNotHeld(); 208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (tcb.priority > this.currentTcb.priority) { 209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return tcb; 210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return this.currentTcb; 212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * Block the currently executing task and return the next task control block 217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * to run. The blocked task will not be made runnable until it is explicitly 218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * released, even if new work is added to it. 219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockScheduler.prototype.holdCurrent = function () { 221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.holdCount++; 222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.currentTcb.markAsHeld(); 223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return this.currentTcb.link; 224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * Suspend the currently executing task and return the next task control block 228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * to run. If new work is added to the suspended task it will be made runnable. 229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockScheduler.prototype.suspendCurrent = function () { 231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.currentTcb.markAsSuspended(); 232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return this.currentTcb; 233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * Add the specified packet to the end of the worklist used by the task 237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * associated with the packet and make the task runnable if it is currently 238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * suspended. 239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {Packet} packet the packet to add 240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockScheduler.prototype.queue = function (packet) { 242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var t = this.blocks[packet.id]; 243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (t == null) return t; 244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.queueCount++; 245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block packet.link = null; 246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block packet.id = this.currentId; 247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return t.checkPriorityAdd(this.currentTcb, packet); 248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * A task control block manages a task and the queue of work packages associated 252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * with it. 253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {TaskControlBlock} link the preceding block in the linked block list 254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} id the id of this block 255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} priority the priority of this block 256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {Packet} queue the queue of packages to be processed by the task 257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {Task} task the task 258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @constructor 259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction TaskControlBlock(link, id, priority, queue, task) { 261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.link = link; 262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.id = id; 263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.priority = priority; 264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.queue = queue; 265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.task = task; 266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (queue == null) { 267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.state = STATE_SUSPENDED; 268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.state = STATE_SUSPENDED_RUNNABLE; 270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * The task is running and is currently scheduled. 275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar STATE_RUNNING = 0; 277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * The task has packets left to process. 280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar STATE_RUNNABLE = 1; 282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * The task is not currently running. The task is not blocked as such and may 285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block* be started by the scheduler. 286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar STATE_SUSPENDED = 2; 288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * The task is blocked and cannot be run until it is explicitly released. 291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar STATE_HELD = 4; 293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar STATE_SUSPENDED_RUNNABLE = STATE_SUSPENDED | STATE_RUNNABLE; 295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar STATE_NOT_HELD = ~STATE_HELD; 296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTaskControlBlock.prototype.setRunning = function () { 298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.state = STATE_RUNNING; 299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTaskControlBlock.prototype.markAsNotHeld = function () { 302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.state = this.state & STATE_NOT_HELD; 303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTaskControlBlock.prototype.markAsHeld = function () { 306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.state = this.state | STATE_HELD; 307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTaskControlBlock.prototype.isHeldOrSuspended = function () { 310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return (this.state & STATE_HELD) != 0 || (this.state == STATE_SUSPENDED); 311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTaskControlBlock.prototype.markAsSuspended = function () { 314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.state = this.state | STATE_SUSPENDED; 315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTaskControlBlock.prototype.markAsRunnable = function () { 318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.state = this.state | STATE_RUNNABLE; 319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * Runs this task, if it is ready to be run, and returns the next task to run. 323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTaskControlBlock.prototype.run = function () { 325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var packet; 326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (this.state == STATE_SUSPENDED_RUNNABLE) { 327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block packet = this.queue; 328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.queue = packet.link; 329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (this.queue == null) { 330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.state = STATE_RUNNING; 331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.state = STATE_RUNNABLE; 333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block packet = null; 336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return this.task.run(packet); 338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * Adds a packet to the worklist of this block's task, marks this as runnable if 342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * necessary, and returns the next runnable object to run (the one 343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * with the highest priority). 344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTaskControlBlock.prototype.checkPriorityAdd = function (task, packet) { 346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (this.queue == null) { 347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.queue = packet; 348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.markAsRunnable(); 349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (this.priority > task.priority) return this; 350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.queue = packet.addTo(this.queue); 352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return task; 354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTaskControlBlock.prototype.toString = function () { 357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "tcb { " + this.task + "@" + this.state + " }"; 358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * An idle task doesn't do any work itself but cycles control between the two 362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * device tasks. 363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {Scheduler} scheduler the scheduler that manages this task 364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} v1 a seed value that controls how the device tasks are scheduled 365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} count the number of times this task should be scheduled 366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @constructor 367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction IdleTask(scheduler, v1, count) { 369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.scheduler = scheduler; 370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.v1 = v1; 371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.count = count; 372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockIdleTask.prototype.run = function (packet) { 375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.count--; 376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (this.count == 0) return this.scheduler.holdCurrent(); 377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if ((this.v1 & 1) == 0) { 378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.v1 = this.v1 >> 1; 379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return this.scheduler.release(ID_DEVICE_A); 380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.v1 = (this.v1 >> 1) ^ 0xD008; 382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return this.scheduler.release(ID_DEVICE_B); 383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockIdleTask.prototype.toString = function () { 387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "IdleTask" 388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * A task that suspends itself after each time it has been run to simulate 392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * waiting for data from an external device. 393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {Scheduler} scheduler the scheduler that manages this task 394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @constructor 395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction DeviceTask(scheduler) { 397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.scheduler = scheduler; 398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.v1 = null; 399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockDeviceTask.prototype.run = function (packet) { 402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (packet == null) { 403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (this.v1 == null) return this.scheduler.suspendCurrent(); 404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var v = this.v1; 405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.v1 = null; 406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return this.scheduler.queue(v); 407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.v1 = packet; 409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return this.scheduler.holdCurrent(); 410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockDeviceTask.prototype.toString = function () { 414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "DeviceTask"; 415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * A task that manipulates work packets. 419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {Scheduler} scheduler the scheduler that manages this task 420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} v1 a seed used to specify how work packets are manipulated 421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} v2 another seed used to specify how work packets are manipulated 422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @constructor 423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction WorkerTask(scheduler, v1, v2) { 425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.scheduler = scheduler; 426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.v1 = v1; 427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.v2 = v2; 428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockWorkerTask.prototype.run = function (packet) { 431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (packet == null) { 432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return this.scheduler.suspendCurrent(); 433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (this.v1 == ID_HANDLER_A) { 435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.v1 = ID_HANDLER_B; 436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.v1 = ID_HANDLER_A; 438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block packet.id = this.v1; 440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block packet.a1 = 0; 441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (var i = 0; i < DATA_SIZE; i++) { 442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.v2++; 443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (this.v2 > 26) this.v2 = 1; 444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block packet.a2[i] = this.v2; 445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return this.scheduler.queue(packet); 447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockWorkerTask.prototype.toString = function () { 451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "WorkerTask"; 452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * A task that manipulates work packets and then suspends itself. 456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {Scheduler} scheduler the scheduler that manages this task 457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @constructor 458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction HandlerTask(scheduler) { 460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.scheduler = scheduler; 461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.v1 = null; 462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.v2 = null; 463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockHandlerTask.prototype.run = function (packet) { 466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (packet != null) { 467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (packet.kind == KIND_WORK) { 468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.v1 = packet.addTo(this.v1); 469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.v2 = packet.addTo(this.v2); 471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (this.v1 != null) { 474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var count = this.v1.a1; 475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var v; 476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (count < DATA_SIZE) { 477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (this.v2 != null) { 478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block v = this.v2; 479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.v2 = this.v2.link; 480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block v.a1 = this.v1.a2[count]; 481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.v1.a1 = count + 1; 482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return this.scheduler.queue(v); 483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block v = this.v1; 486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.v1 = this.v1.link; 487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return this.scheduler.queue(v); 488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return this.scheduler.suspendCurrent(); 491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockHandlerTask.prototype.toString = function () { 494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "HandlerTask"; 495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/* --- * 498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * P a c k e t 499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * --- */ 500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar DATA_SIZE = 4; 502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * A simple package of data that is manipulated by the tasks. The exact layout 505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * of the payload data carried by a packet is not importaint, and neither is the 506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * nature of the work performed on packets by the tasks. 507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * 508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * Besides carrying data, packets form linked lists and are hence used both as 509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * data and worklists. 510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {Packet} link the tail of the linked list of packets 511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} id an ID for this packet 512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {int} kind the type of this packet 513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @constructor 514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction Packet(link, id, kind) { 516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.link = link; 517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.id = id; 518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.kind = kind; 519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.a1 = 0; 520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.a2 = new Array(DATA_SIZE); 521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block/** 524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * Add this packet to the end of a worklist, and return the worklist. 525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * @param {Packet} queue the worklist to add this packet to 526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block */ 527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockPacket.prototype.addTo = function (queue) { 528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.link = null; 529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (queue == null) return this; 530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var peek, next = queue; 531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while ((peek = next.link) != null) 532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block next = peek; 533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block next.link = this; 534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return queue; 535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockPacket.prototype.toString = function () { 538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "Packet"; 539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 540