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