10bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch// Copyright 2006-2008 the V8 project authors. All rights reserved.
2563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// Redistribution and use in source and binary forms, with or without
3563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// modification, are permitted provided that the following conditions are
4563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// met:
5563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark//
6563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark//     * Redistributions of source code must retain the above copyright
7563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark//       notice, this list of conditions and the following disclaimer.
8563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark//     * Redistributions in binary form must reproduce the above
9563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark//       copyright notice, this list of conditions and the following
10563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark//       disclaimer in the documentation and/or other materials provided
11563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark//       with the distribution.
12563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark//     * Neither the name of Google Inc. nor the names of its
13563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark//       contributors may be used to endorse or promote products derived
14563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark//       from this software without specific prior written permission.
15563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark//
16563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
28563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
29563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// This is a JavaScript implementation of the Richards
30563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// benchmark from:
31563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark//
32563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark//    http://www.cl.cam.ac.uk/~mr10/Bench.html
330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch//
34563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// The benchmark was originally implemented in BCPL by
35563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// Martin Richards.
36563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
38563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
39563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * The Richards benchmark simulates the task dispatcher of an
40563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * operating system.
41563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark **/
42563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkfunction runRichards() {
43563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  var scheduler = new Scheduler();
44563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  scheduler.addIdleTask(ID_IDLE, 0, null, COUNT);
45563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
46563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  var queue = new Packet(null, ID_WORKER, KIND_WORK);
47563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  queue = new Packet(queue,  ID_WORKER, KIND_WORK);
48563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  scheduler.addWorkerTask(ID_WORKER, 1000, queue);
49563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
50563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  queue = new Packet(null, ID_DEVICE_A, KIND_DEVICE);
51563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  queue = new Packet(queue,  ID_DEVICE_A, KIND_DEVICE);
52563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  queue = new Packet(queue,  ID_DEVICE_A, KIND_DEVICE);
53563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  scheduler.addHandlerTask(ID_HANDLER_A, 2000, queue);
54563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
55563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  queue = new Packet(null, ID_DEVICE_B, KIND_DEVICE);
56563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  queue = new Packet(queue,  ID_DEVICE_B, KIND_DEVICE);
57563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  queue = new Packet(queue,  ID_DEVICE_B, KIND_DEVICE);
58563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  scheduler.addHandlerTask(ID_HANDLER_B, 3000, queue);
59563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
60563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  scheduler.addDeviceTask(ID_DEVICE_A, 4000, null);
61563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
62563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  scheduler.addDeviceTask(ID_DEVICE_B, 5000, null);
63563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
64563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  scheduler.schedule();
65563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
66563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  if (scheduler.queueCount != EXPECTED_QUEUE_COUNT ||
67563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      scheduler.holdCount != EXPECTED_HOLD_COUNT) {
68563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    var msg =
69563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        "Error during execution: queueCount = " + scheduler.queueCount +
70563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        ", holdCount = " + scheduler.holdCount + ".";
710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    throw new Error(msg);
72563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  }
73563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
74563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
75563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar COUNT = 1000;
76563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
77563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
78563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * These two constants specify how many times a packet is queued and
79563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * how many times a task is put on hold in a correct run of richards.
80563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * They don't have any meaning a such but are characteristic of a
81563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * correct run so if the actual queue or hold count is different from
82563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * the expected there must be a bug in the implementation.
83563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark **/
84563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar EXPECTED_QUEUE_COUNT = 2322;
85563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar EXPECTED_HOLD_COUNT = 928;
86563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
87563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
88563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
89563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * A scheduler can be used to schedule a set of tasks based on their relative
90563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * priorities.  Scheduling is done by maintaining a list of task control blocks
91563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * which holds tasks and the data queue they are processing.
92563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @constructor
93563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
94563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkfunction Scheduler() {
95563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.queueCount = 0;
96563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.holdCount = 0;
97563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.blocks = new Array(NUMBER_OF_IDS);
98563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.list = null;
99563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.currentTcb = null;
100563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.currentId = null;
101563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
102563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
103563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar ID_IDLE       = 0;
104563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar ID_WORKER     = 1;
105563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar ID_HANDLER_A  = 2;
106563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar ID_HANDLER_B  = 3;
107563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar ID_DEVICE_A   = 4;
108563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar ID_DEVICE_B   = 5;
109563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar NUMBER_OF_IDS = 6;
110563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
111563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar KIND_DEVICE   = 0;
112563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar KIND_WORK     = 1;
113563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
114563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
115563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Add an idle task to this scheduler.
116563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} id the identity of the task
117563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} priority the task's priority
118563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {Packet} queue the queue of work to be processed by the task
119563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} count the number of times to schedule the task
120563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
121563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkScheduler.prototype.addIdleTask = function (id, priority, queue, count) {
122563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.addRunningTask(id, priority, queue, new IdleTask(this, 1, count));
123563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
124563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
125563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
126563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Add a work task to this scheduler.
127563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} id the identity of the task
128563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} priority the task's priority
129563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {Packet} queue the queue of work to be processed by the task
130563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
131563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkScheduler.prototype.addWorkerTask = function (id, priority, queue) {
132563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.addTask(id, priority, queue, new WorkerTask(this, ID_HANDLER_A, 0));
133563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
134563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
135563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
136563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Add a handler task to this scheduler.
137563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} id the identity of the task
138563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} priority the task's priority
139563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {Packet} queue the queue of work to be processed by the task
140563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
141563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkScheduler.prototype.addHandlerTask = function (id, priority, queue) {
142563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.addTask(id, priority, queue, new HandlerTask(this));
143563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
144563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
145563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
146563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Add a handler task to this scheduler.
147563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} id the identity of the task
148563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} priority the task's priority
149563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {Packet} queue the queue of work to be processed by the task
150563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
151563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkScheduler.prototype.addDeviceTask = function (id, priority, queue) {
152563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.addTask(id, priority, queue, new DeviceTask(this))
153563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
154563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
155563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
156563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Add the specified task and mark it as running.
157563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} id the identity of the task
158563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} priority the task's priority
159563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {Packet} queue the queue of work to be processed by the task
160563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {Task} task the task to add
161563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
162563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkScheduler.prototype.addRunningTask = function (id, priority, queue, task) {
163563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.addTask(id, priority, queue, task);
164563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.currentTcb.setRunning();
165563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
166563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
167563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
168563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Add the specified task to this scheduler.
169563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} id the identity of the task
170563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} priority the task's priority
171563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {Packet} queue the queue of work to be processed by the task
172563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {Task} task the task to add
173563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
174563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkScheduler.prototype.addTask = function (id, priority, queue, task) {
175563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.currentTcb = new TaskControlBlock(this.list, id, priority, queue, task);
176563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.list = this.currentTcb;
177563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.blocks[id] = this.currentTcb;
178563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
179563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
180563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
181563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Execute the tasks managed by this scheduler.
182563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
183563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkScheduler.prototype.schedule = function () {
184563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.currentTcb = this.list;
185563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  while (this.currentTcb != null) {
186563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    if (this.currentTcb.isHeldOrSuspended()) {
187563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      this.currentTcb = this.currentTcb.link;
188563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    } else {
189563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      this.currentId = this.currentTcb.id;
190563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      this.currentTcb = this.currentTcb.run();
191563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    }
192563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  }
193563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
194563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
195563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
196563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Release a task that is currently blocked and return the next block to run.
197563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} id the id of the task to suspend
198563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
199563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkScheduler.prototype.release = function (id) {
200563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  var tcb = this.blocks[id];
201563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  if (tcb == null) return tcb;
202563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  tcb.markAsNotHeld();
203563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  if (tcb.priority > this.currentTcb.priority) {
204563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    return tcb;
205563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  } else {
206563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    return this.currentTcb;
207563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  }
208563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
209563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
210563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
211563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Block the currently executing task and return the next task control block
212563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * to run.  The blocked task will not be made runnable until it is explicitly
213563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * released, even if new work is added to it.
214563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
215563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkScheduler.prototype.holdCurrent = function () {
216563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.holdCount++;
217563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.currentTcb.markAsHeld();
218563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  return this.currentTcb.link;
219563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
220563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
221563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
222563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Suspend the currently executing task and return the next task control block
223563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * to run.  If new work is added to the suspended task it will be made runnable.
224563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
225563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkScheduler.prototype.suspendCurrent = function () {
226563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.currentTcb.markAsSuspended();
227563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  return this.currentTcb;
228563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
229563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
230563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
231563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Add the specified packet to the end of the worklist used by the task
232563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * associated with the packet and make the task runnable if it is currently
233563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * suspended.
234563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {Packet} packet the packet to add
235563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
236563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkScheduler.prototype.queue = function (packet) {
237563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  var t = this.blocks[packet.id];
238563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  if (t == null) return t;
239563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.queueCount++;
240563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  packet.link = null;
241563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  packet.id = this.currentId;
242563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  return t.checkPriorityAdd(this.currentTcb, packet);
243563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
244563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
245563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
246563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * A task control block manages a task and the queue of work packages associated
247563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * with it.
248563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {TaskControlBlock} link the preceding block in the linked block list
249563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} id the id of this block
250563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} priority the priority of this block
251563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {Packet} queue the queue of packages to be processed by the task
252563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {Task} task the task
253563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @constructor
254563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
255563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkfunction TaskControlBlock(link, id, priority, queue, task) {
256563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.link = link;
257563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.id = id;
258563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.priority = priority;
259563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.queue = queue;
260563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.task = task;
261563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  if (queue == null) {
262563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    this.state = STATE_SUSPENDED;
263563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  } else {
264563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    this.state = STATE_SUSPENDED_RUNNABLE;
265563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  }
266563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
267563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
268563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
269563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * The task is running and is currently scheduled.
270563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
271563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar STATE_RUNNING = 0;
272563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
273563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
274563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * The task has packets left to process.
275563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
276563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar STATE_RUNNABLE = 1;
277563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
278563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
279563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * The task is not currently running.  The task is not blocked as such and may
280563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark* be started by the scheduler.
281563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
282563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar STATE_SUSPENDED = 2;
283563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
284563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
285563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * The task is blocked and cannot be run until it is explicitly released.
286563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
287563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar STATE_HELD = 4;
288563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
289563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar STATE_SUSPENDED_RUNNABLE = STATE_SUSPENDED | STATE_RUNNABLE;
290563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar STATE_NOT_HELD = ~STATE_HELD;
291563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
292563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkTaskControlBlock.prototype.setRunning = function () {
293563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.state = STATE_RUNNING;
294563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
295563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
296563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkTaskControlBlock.prototype.markAsNotHeld = function () {
297563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.state = this.state & STATE_NOT_HELD;
298563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
299563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
300563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkTaskControlBlock.prototype.markAsHeld = function () {
301563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.state = this.state | STATE_HELD;
302563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
303563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
304563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkTaskControlBlock.prototype.isHeldOrSuspended = function () {
305563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  return (this.state & STATE_HELD) != 0 || (this.state == STATE_SUSPENDED);
306563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
307563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
308563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkTaskControlBlock.prototype.markAsSuspended = function () {
309563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.state = this.state | STATE_SUSPENDED;
310563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
311563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
312563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkTaskControlBlock.prototype.markAsRunnable = function () {
313563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.state = this.state | STATE_RUNNABLE;
314563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
315563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
316563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
317563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Runs this task, if it is ready to be run, and returns the next task to run.
318563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
319563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkTaskControlBlock.prototype.run = function () {
320563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  var packet;
321563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  if (this.state == STATE_SUSPENDED_RUNNABLE) {
322563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    packet = this.queue;
323563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    this.queue = packet.link;
324563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    if (this.queue == null) {
325563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      this.state = STATE_RUNNING;
326563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    } else {
327563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      this.state = STATE_RUNNABLE;
328563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    }
329563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  } else {
330563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    packet = null;
331563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  }
332563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  return this.task.run(packet);
333563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
334563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
335563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
336563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Adds a packet to the worklist of this block's task, marks this as runnable if
337563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * necessary, and returns the next runnable object to run (the one
338563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * with the highest priority).
339563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
340563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkTaskControlBlock.prototype.checkPriorityAdd = function (task, packet) {
341563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  if (this.queue == null) {
342563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    this.queue = packet;
343563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    this.markAsRunnable();
344563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    if (this.priority > task.priority) return this;
345563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  } else {
346563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    this.queue = packet.addTo(this.queue);
347563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  }
348563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  return task;
349563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
350563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
351563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkTaskControlBlock.prototype.toString = function () {
352563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  return "tcb { " + this.task + "@" + this.state + " }";
353563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
354563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
355563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
356563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * An idle task doesn't do any work itself but cycles control between the two
357563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * device tasks.
358563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {Scheduler} scheduler the scheduler that manages this task
359563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} v1 a seed value that controls how the device tasks are scheduled
360563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} count the number of times this task should be scheduled
361563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @constructor
362563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
363563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkfunction IdleTask(scheduler, v1, count) {
364563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.scheduler = scheduler;
365563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.v1 = v1;
366563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.count = count;
367563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
368563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
369563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkIdleTask.prototype.run = function (packet) {
370563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.count--;
371563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  if (this.count == 0) return this.scheduler.holdCurrent();
372563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  if ((this.v1 & 1) == 0) {
373563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    this.v1 = this.v1 >> 1;
374563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    return this.scheduler.release(ID_DEVICE_A);
375563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  } else {
376563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    this.v1 = (this.v1 >> 1) ^ 0xD008;
377563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    return this.scheduler.release(ID_DEVICE_B);
378563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  }
379563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
380563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
381563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkIdleTask.prototype.toString = function () {
382563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  return "IdleTask"
383563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
384563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
385563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
386563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * A task that suspends itself after each time it has been run to simulate
387563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * waiting for data from an external device.
388563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {Scheduler} scheduler the scheduler that manages this task
389563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @constructor
390563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
391563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkfunction DeviceTask(scheduler) {
392563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.scheduler = scheduler;
393563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.v1 = null;
394563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
395563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
396563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkDeviceTask.prototype.run = function (packet) {
397563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  if (packet == null) {
398563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    if (this.v1 == null) return this.scheduler.suspendCurrent();
399563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    var v = this.v1;
400563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    this.v1 = null;
401563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    return this.scheduler.queue(v);
402563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  } else {
403563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    this.v1 = packet;
404563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    return this.scheduler.holdCurrent();
405563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  }
406563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
407563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
408563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkDeviceTask.prototype.toString = function () {
409563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  return "DeviceTask";
410563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
411563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
412563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
413563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * A task that manipulates work packets.
414563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {Scheduler} scheduler the scheduler that manages this task
415563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} v1 a seed used to specify how work packets are manipulated
416563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} v2 another seed used to specify how work packets are manipulated
417563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @constructor
418563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
419563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkfunction WorkerTask(scheduler, v1, v2) {
420563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.scheduler = scheduler;
421563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.v1 = v1;
422563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.v2 = v2;
423563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
424563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
425563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkWorkerTask.prototype.run = function (packet) {
426563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  if (packet == null) {
427563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    return this.scheduler.suspendCurrent();
428563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  } else {
429563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    if (this.v1 == ID_HANDLER_A) {
430563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      this.v1 = ID_HANDLER_B;
431563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    } else {
432563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      this.v1 = ID_HANDLER_A;
433563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    }
434563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    packet.id = this.v1;
435563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    packet.a1 = 0;
436563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    for (var i = 0; i < DATA_SIZE; i++) {
437563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      this.v2++;
438563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      if (this.v2 > 26) this.v2 = 1;
439563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      packet.a2[i] = this.v2;
440563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    }
441563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    return this.scheduler.queue(packet);
442563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  }
443563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
444563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
445563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkWorkerTask.prototype.toString = function () {
446563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  return "WorkerTask";
447563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
448563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
449563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
450563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * A task that manipulates work packets and then suspends itself.
451563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {Scheduler} scheduler the scheduler that manages this task
452563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @constructor
453563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
454563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkfunction HandlerTask(scheduler) {
455563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.scheduler = scheduler;
456563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.v1 = null;
457563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.v2 = null;
458563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
459563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
460563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkHandlerTask.prototype.run = function (packet) {
461563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  if (packet != null) {
462563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    if (packet.kind == KIND_WORK) {
463563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      this.v1 = packet.addTo(this.v1);
464563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    } else {
465563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      this.v2 = packet.addTo(this.v2);
466563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    }
467563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  }
468563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  if (this.v1 != null) {
469563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    var count = this.v1.a1;
470563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    var v;
471563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    if (count < DATA_SIZE) {
472563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      if (this.v2 != null) {
473563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        v = this.v2;
474563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        this.v2 = this.v2.link;
475563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        v.a1 = this.v1.a2[count];
476563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        this.v1.a1 = count + 1;
477563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        return this.scheduler.queue(v);
478563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      }
479563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    } else {
480563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      v = this.v1;
481563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      this.v1 = this.v1.link;
482563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      return this.scheduler.queue(v);
483563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    }
484563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  }
485563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  return this.scheduler.suspendCurrent();
486563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
487563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
488563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkHandlerTask.prototype.toString = function () {
489563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  return "HandlerTask";
490563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
491563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
492563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/* --- *
493563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * P a c k e t
494563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * --- */
495563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
496563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvar DATA_SIZE = 4;
497563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
498563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
499563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * A simple package of data that is manipulated by the tasks.  The exact layout
500563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * of the payload data carried by a packet is not importaint, and neither is the
501563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * nature of the work performed on packets by the tasks.
502563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark *
503563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Besides carrying data, packets form linked lists and are hence used both as
504563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * data and worklists.
505563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {Packet} link the tail of the linked list of packets
506563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} id an ID for this packet
507563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {int} kind the type of this packet
508563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @constructor
509563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
510563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkfunction Packet(link, id, kind) {
511563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.link = link;
512563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.id = id;
513563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.kind = kind;
514563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.a1 = 0;
515563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.a2 = new Array(DATA_SIZE);
516563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
517563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
518563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/**
519563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Add this packet to the end of a worklist, and return the worklist.
520563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * @param {Packet} queue the worklist to add this packet to
521563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
522563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkPacket.prototype.addTo = function (queue) {
523563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  this.link = null;
524563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  if (queue == null) return this;
525563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  var peek, next = queue;
526563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  while ((peek = next.link) != null)
527563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    next = peek;
528563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  next.link = this;
529563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  return queue;
530563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
531563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
532563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkPacket.prototype.toString = function () {
533563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  return "Packet";
534563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
535563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
536563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkfor (var i = 0; i < 350; ++i)
537563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark  runRichards();
538