From 2d4c54508949201a85f44e50d7bf675b2f94662d Mon Sep 17 00:00:00 2001 From: Andrew Morris Date: Wed, 21 Jun 2023 09:51:42 +1000 Subject: [PATCH] Port to typescript --- benchmarks/richards/richards.ts | 880 +++++++++++++++++--------------- 1 file changed, 482 insertions(+), 398 deletions(-) diff --git a/benchmarks/richards/richards.ts b/benchmarks/richards/richards.ts index d94da9d..4a79e99 100644 --- a/benchmarks/richards/richards.ts +++ b/benchmarks/richards/richards.ts @@ -33,9 +33,9 @@ // The benchmark was originally implemented in BCPL by // Martin Richards. -var Richards = new BenchmarkSuite("Richards", [35302], [ - new Benchmark("Richards", true, false, 8200, runRichards), -]); +// var Richards = new BenchmarkSuite("Richards", [35302], [ +// new Benchmark("Richards", true, false, 8200, runRichards), +// ]); /** * The Richards benchmark simulates the task dispatcher of an @@ -43,31 +43,31 @@ var Richards = new BenchmarkSuite("Richards", [35302], [ */ function runRichards() { var scheduler = new Scheduler(); - scheduler.addIdleTask(ID_IDLE, 0, null, COUNT); + scheduler.addIdleTask(0, /* ID_IDLE */ 0, null, 1000 /* COUNT */); - var queue = new Packet(null, ID_WORKER, KIND_WORK); - queue = new Packet(queue, ID_WORKER, KIND_WORK); - scheduler.addWorkerTask(ID_WORKER, 1000, queue); + var queue = new Packet(null, 1, /* ID_WORKER */ 1 /* KIND_WORK */); + queue = new Packet(queue, 1, /* ID_WORKER */ 1 /* KIND_WORK */); + scheduler.addWorkerTask(1, /* ID_WORKER */ 1000, queue); - queue = new Packet(null, ID_DEVICE_A, KIND_DEVICE); - queue = new Packet(queue, ID_DEVICE_A, KIND_DEVICE); - queue = new Packet(queue, ID_DEVICE_A, KIND_DEVICE); - scheduler.addHandlerTask(ID_HANDLER_A, 2000, queue); + queue = new Packet(null, 4, /* ID_DEVICE_A */ 0 /* KIND_DEVICE */); + queue = new Packet(queue, 4, /* ID_DEVICE_A */ 0 /* KIND_DEVICE */); + queue = new Packet(queue, 4, /* ID_DEVICE_A */ 0 /* KIND_DEVICE */); + scheduler.addHandlerTask(2, /* ID_HANDLER_A */ 2000, queue); - queue = new Packet(null, ID_DEVICE_B, KIND_DEVICE); - queue = new Packet(queue, ID_DEVICE_B, KIND_DEVICE); - queue = new Packet(queue, ID_DEVICE_B, KIND_DEVICE); - scheduler.addHandlerTask(ID_HANDLER_B, 3000, queue); + queue = new Packet(null, 5, /* ID_DEVICE_B */ 0 /* KIND_DEVICE */); + queue = new Packet(queue, 5, /* ID_DEVICE_B */ 0 /* KIND_DEVICE */); + queue = new Packet(queue, 5, /* ID_DEVICE_B */ 0 /* KIND_DEVICE */); + scheduler.addHandlerTask(3, /* ID_HANDLER_B */ 3000, queue); - scheduler.addDeviceTask(ID_DEVICE_A, 4000, null); + scheduler.addDeviceTask(4, /* ID_DEVICE_A */ 4000, null); - scheduler.addDeviceTask(ID_DEVICE_B, 5000, null); + scheduler.addDeviceTask(5, /* ID_DEVICE_B */ 5000, null); scheduler.schedule(); if ( - scheduler.queueCount != EXPECTED_QUEUE_COUNT || - scheduler.holdCount != EXPECTED_HOLD_COUNT + scheduler.queueCount != 2322 /* EXPECTED_QUEUE_COUNT */ || + scheduler.holdCount != 928 /* EXPECTED_HOLD_COUNT */ ) { var msg = "Error during execution: queueCount = " + scheduler.queueCount + ", holdCount = " + scheduler.holdCount + "."; @@ -75,7 +75,7 @@ function runRichards() { } } -var COUNT = 1000; +// var COUNT = 1000; /** * These two constants specify how many times a packet is queued and @@ -84,454 +84,538 @@ var COUNT = 1000; * correct run so if the actual queue or hold count is different from * the expected there must be a bug in the implementation. */ -var EXPECTED_QUEUE_COUNT = 2322; -var EXPECTED_HOLD_COUNT = 928; +// var EXPECTED_QUEUE_COUNT = 2322; +// var EXPECTED_HOLD_COUNT = 928; /** * A scheduler can be used to schedule a set of tasks based on their relative * priorities. Scheduling is done by maintaining a list of task control blocks * which holds tasks and the data queue they are processing. - * @constructor */ -function Scheduler() { - this.queueCount = 0; - this.holdCount = 0; - this.blocks = new Array(NUMBER_OF_IDS); - this.list = null; - this.currentTcb = null; - this.currentId = null; -} +class Scheduler { + queueCount = 0; + holdCount = 0; + blocks = new Array(6 /* NUMBER_OF_IDS */); + list: TaskControlBlock | null = null; + currentTcb: TaskControlBlock | null = null; + currentId: number | null = null; -var ID_IDLE = 0; -var ID_WORKER = 1; -var ID_HANDLER_A = 2; -var ID_HANDLER_B = 3; -var ID_DEVICE_A = 4; -var ID_DEVICE_B = 5; -var NUMBER_OF_IDS = 6; + // var ID_IDLE = 0; + // var ID_WORKER = 1; + // var ID_HANDLER_A = 2; + // var ID_HANDLER_B = 3; + // var ID_DEVICE_A = 4; + // var ID_DEVICE_B = 5; + // var NUMBER_OF_IDS = 6; -var KIND_DEVICE = 0; -var KIND_WORK = 1; + // var KIND_DEVICE = 0; + // var KIND_WORK = 1; -/** - * Add an idle task to this scheduler. - * @param {int} id the identity of the task - * @param {int} priority the task's priority - * @param {Packet} queue the queue of work to be processed by the task - * @param {int} count the number of times to schedule the task - */ -Scheduler.prototype.addIdleTask = function (id, priority, queue, count) { - this.addRunningTask(id, priority, queue, new IdleTask(this, 1, count)); -}; + /** + * Add an idle task to this scheduler. + * @param {int} id the identity of the task + * @param {int} priority the task's priority + * @param {Packet} queue the queue of work to be processed by the task + * @param {int} count the number of times to schedule the task + */ + addIdleTask( + id: number, + priority: number, + queue: Packet | null, + count: number, + ) { + this.addRunningTask(id, priority, queue, new IdleTask(this, 1, count)); + } -/** - * Add a work task to this scheduler. - * @param {int} id the identity of the task - * @param {int} priority the task's priority - * @param {Packet} queue the queue of work to be processed by the task - */ -Scheduler.prototype.addWorkerTask = function (id, priority, queue) { - this.addTask(id, priority, queue, new WorkerTask(this, ID_HANDLER_A, 0)); -}; + /** + * Add a work task to this scheduler. + * @param {int} id the identity of the task + * @param {int} priority the task's priority + * @param {Packet} queue the queue of work to be processed by the task + */ + addWorkerTask(id: number, priority: number, queue: Packet) { + this.addTask( + id, + priority, + queue, + new WorkerTask(this, 2, /* ID_HANDLER_A */ 0), + ); + } -/** - * Add a handler task to this scheduler. - * @param {int} id the identity of the task - * @param {int} priority the task's priority - * @param {Packet} queue the queue of work to be processed by the task - */ -Scheduler.prototype.addHandlerTask = function (id, priority, queue) { - this.addTask(id, priority, queue, new HandlerTask(this)); -}; + /** + * Add a handler task to this scheduler. + * @param {int} id the identity of the task + * @param {int} priority the task's priority + * @param {Packet} queue the queue of work to be processed by the task + */ + addHandlerTask(id: number, priority: number, queue: Packet) { + this.addTask(id, priority, queue, new HandlerTask(this)); + } -/** - * Add a handler task to this scheduler. - * @param {int} id the identity of the task - * @param {int} priority the task's priority - * @param {Packet} queue the queue of work to be processed by the task - */ -Scheduler.prototype.addDeviceTask = function (id, priority, queue) { - this.addTask(id, priority, queue, new DeviceTask(this)); -}; + /** + * Add a handler task to this scheduler. + * @param {int} id the identity of the task + * @param {int} priority the task's priority + * @param {Packet} queue the queue of work to be processed by the task + */ + addDeviceTask(id: number, priority: number, queue: Packet | null) { + this.addTask(id, priority, queue, new DeviceTask(this)); + } -/** - * Add the specified task and mark it as running. - * @param {int} id the identity of the task - * @param {int} priority the task's priority - * @param {Packet} queue the queue of work to be processed by the task - * @param {Task} task the task to add - */ -Scheduler.prototype.addRunningTask = function (id, priority, queue, task) { - this.addTask(id, priority, queue, task); - this.currentTcb.setRunning(); -}; + /** + * Add the specified task and mark it as running. + * @param {int} id the identity of the task + * @param {int} priority the task's priority + * @param {Packet} queue the queue of work to be processed by the task + * @param {Task} task the task to add + */ + addRunningTask( + id: number, + priority: number, + queue: Packet | null, + task: Task, + ) { + this.addTask(id, priority, queue, task); + this.currentTcb!.setRunning(); + } -/** - * Add the specified task to this scheduler. - * @param {int} id the identity of the task - * @param {int} priority the task's priority - * @param {Packet} queue the queue of work to be processed by the task - * @param {Task} task the task to add - */ -Scheduler.prototype.addTask = function (id, priority, queue, task) { - this.currentTcb = new TaskControlBlock(this.list, id, priority, queue, task); - this.list = this.currentTcb; - this.blocks[id] = this.currentTcb; -}; + /** + * Add the specified task to this scheduler. + * @param {int} id the identity of the task + * @param {int} priority the task's priority + * @param {Packet} queue the queue of work to be processed by the task + * @param {Task} task the task to add + */ + addTask(id: number, priority: number, queue: Packet | null, task: Task) { + this.currentTcb = new TaskControlBlock( + this.list, + id, + priority, + queue, + task, + ); + this.list = this.currentTcb; + this.blocks[id] = this.currentTcb; + } -/** - * Execute the tasks managed by this scheduler. - */ -Scheduler.prototype.schedule = function () { - this.currentTcb = this.list; - while (this.currentTcb != null) { - if (this.currentTcb.isHeldOrSuspended()) { - this.currentTcb = this.currentTcb.link; - } else { - this.currentId = this.currentTcb.id; - this.currentTcb = this.currentTcb.run(); + /** + * Execute the tasks managed by this scheduler. + */ + schedule() { + this.currentTcb = this.list; + while (this.currentTcb != null) { + if (this.currentTcb.isHeldOrSuspended()) { + this.currentTcb = this.currentTcb.link; + } else { + this.currentId = this.currentTcb.id; + this.currentTcb = this.currentTcb.run(); + } } } -}; -/** - * Release a task that is currently blocked and return the next block to run. - * @param {int} id the id of the task to suspend - */ -Scheduler.prototype.release = function (id) { - var tcb = this.blocks[id]; - if (tcb == null) return tcb; - tcb.markAsNotHeld(); - if (tcb.priority > this.currentTcb.priority) { - return tcb; - } else { + /** + * Release a task that is currently blocked and return the next block to run. + * @param {int} id the id of the task to suspend + */ + release(id: number) { + var tcb = this.blocks[id]; + if (tcb == null) return tcb; + tcb.markAsNotHeld(); + if (tcb.priority > this.currentTcb!.priority) { + return tcb; + } else { + return this.currentTcb; + } + } + + /** + * Block the currently executing task and return the next task control block + * to run. The blocked task will not be made runnable until it is explicitly + * released, even if new work is added to it. + */ + holdCurrent() { + this.holdCount++; + this.currentTcb!.markAsHeld(); + return this.currentTcb!.link; + } + + /** + * Suspend the currently executing task and return the next task control block + * to run. If new work is added to the suspended task it will be made runnable. + */ + suspendCurrent() { + this.currentTcb!.markAsSuspended(); return this.currentTcb; } -}; -/** - * Block the currently executing task and return the next task control block - * to run. The blocked task will not be made runnable until it is explicitly - * released, even if new work is added to it. - */ -Scheduler.prototype.holdCurrent = function () { - this.holdCount++; - this.currentTcb.markAsHeld(); - return this.currentTcb.link; -}; - -/** - * Suspend the currently executing task and return the next task control block - * to run. If new work is added to the suspended task it will be made runnable. - */ -Scheduler.prototype.suspendCurrent = function () { - this.currentTcb.markAsSuspended(); - return this.currentTcb; -}; - -/** - * Add the specified packet to the end of the worklist used by the task - * associated with the packet and make the task runnable if it is currently - * suspended. - * @param {Packet} packet the packet to add - */ -Scheduler.prototype.queue = function (packet) { - var t = this.blocks[packet.id]; - if (t == null) return t; - this.queueCount++; - packet.link = null; - packet.id = this.currentId; - return t.checkPriorityAdd(this.currentTcb, packet); -}; + /** + * Add the specified packet to the end of the worklist used by the task + * associated with the packet and make the task runnable if it is currently + * suspended. + * @param {Packet} packet the packet to add + */ + queue(packet: Packet) { + var t = this.blocks[packet.id!]; + if (t == null) return t; + this.queueCount++; + packet.link = null; + packet.id = this.currentId; + return t.checkPriorityAdd(this.currentTcb, packet); + } +} /** * A task control block manages a task and the queue of work packages associated * with it. - * @param {TaskControlBlock} link the preceding block in the linked block list - * @param {int} id the id of this block - * @param {int} priority the priority of this block - * @param {Packet} queue the queue of packages to be processed by the task - * @param {Task} task the task - * @constructor */ -function TaskControlBlock(link, id, priority, queue, task) { - this.link = link; - this.id = id; - this.priority = priority; - this.queue = queue; - this.task = task; - if (queue == null) { - this.state = STATE_SUSPENDED; - } else { - this.state = STATE_SUSPENDED_RUNNABLE; +class TaskControlBlock { + link: TaskControlBlock | null; + id: number; + priority: number; + queue: Packet | null; + task: Task; + state: number; + + /** + * @param {TaskControlBlock} link the preceding block in the linked block list + * @param {int} id the id of this block + * @param {int} priority the priority of this block + * @param {Packet} queue the queue of packages to be processed by the task + * @param {Task} task the task + * @constructor + */ + constructor( + link: TaskControlBlock | null, + id: number, + priority: number, + queue: Packet | null, + task: Task, + ) { + this.link = link; + this.id = id; + this.priority = priority; + this.queue = queue; + this.task = task; + + if (queue == null) { + this.state = 2 /* STATE_SUSPENDED */; + } else { + this.state = 3 /* STATE_SUSPENDED_RUNNABLE */; + } + } + + /** + * The task is running and is currently scheduled. + */ + // var STATE_RUNNING = 0; + + /** + * The task has packets left to process. + */ + // var STATE_RUNNABLE = 1; + + /** + * The task is not currently running. The task is not blocked as such and may + * be started by the scheduler. + */ + // var STATE_SUSPENDED = 2; + + /** + * The task is blocked and cannot be run until it is explicitly released. + */ + // var STATE_HELD = 4; + + // var STATE_SUSPENDED_RUNNABLE = 2 /* STATE_SUSPENDED */ | 1 /* STATE_RUNNABLE */; + // var STATE_NOT_HELD = ~4 /* STATE_HELD */; + + setRunning() { + this.state = 0 /* STATE_RUNNING */; + } + + markAsNotHeld() { + this.state = this.state & (-5) /* STATE_NOT_HELD */; + } + + markAsHeld() { + this.state = this.state | 4 /* STATE_HELD */; + } + + isHeldOrSuspended() { + return (this.state & 4 /* STATE_HELD */) != 0 || + (this.state == 2 /* STATE_SUSPENDED */); + } + + markAsSuspended() { + this.state = this.state | 2 /* STATE_SUSPENDED */; + } + + markAsRunnable() { + this.state = this.state | 1 /* STATE_RUNNABLE */; + } + + /** + * Runs this task, if it is ready to be run, and returns the next task to run. + */ + run() { + var packet; + if (this.state == 3 /* STATE_SUSPENDED_RUNNABLE */) { + packet = this.queue; + this.queue = packet!.link; + if (this.queue == null) { + this.state = 0 /* STATE_RUNNING */; + } else { + this.state = 1 /* STATE_RUNNABLE */; + } + } else { + packet = null; + } + return this.task.run(packet); + } + + /** + * Adds a packet to the worklist of this block's task, marks this as runnable if + * necessary, and returns the next runnable object to run (the one + * with the highest priority). + */ + checkPriorityAdd(task: TaskControlBlock, packet: Packet) { + if (this.queue == null) { + this.queue = packet; + this.markAsRunnable(); + if (this.priority > task.priority) return this; + } else { + this.queue = packet.addTo(this.queue); + } + return task; + } + + toString() { + return "tcb { " + this.task + "@" + this.state + " }"; } } -/** - * The task is running and is currently scheduled. - */ -var STATE_RUNNING = 0; - -/** - * The task has packets left to process. - */ -var STATE_RUNNABLE = 1; - -/** - * The task is not currently running. The task is not blocked as such and may - * be started by the scheduler. - */ -var STATE_SUSPENDED = 2; - -/** - * The task is blocked and cannot be run until it is explicitly released. - */ -var STATE_HELD = 4; - -var STATE_SUSPENDED_RUNNABLE = STATE_SUSPENDED | STATE_RUNNABLE; -var STATE_NOT_HELD = ~STATE_HELD; - -TaskControlBlock.prototype.setRunning = function () { - this.state = STATE_RUNNING; -}; - -TaskControlBlock.prototype.markAsNotHeld = function () { - this.state = this.state & STATE_NOT_HELD; -}; - -TaskControlBlock.prototype.markAsHeld = function () { - this.state = this.state | STATE_HELD; -}; - -TaskControlBlock.prototype.isHeldOrSuspended = function () { - return (this.state & STATE_HELD) != 0 || (this.state == STATE_SUSPENDED); -}; - -TaskControlBlock.prototype.markAsSuspended = function () { - this.state = this.state | STATE_SUSPENDED; -}; - -TaskControlBlock.prototype.markAsRunnable = function () { - this.state = this.state | STATE_RUNNABLE; -}; - -/** - * Runs this task, if it is ready to be run, and returns the next task to run. - */ -TaskControlBlock.prototype.run = function () { - var packet; - if (this.state == STATE_SUSPENDED_RUNNABLE) { - packet = this.queue; - this.queue = packet.link; - if (this.queue == null) { - this.state = STATE_RUNNING; - } else { - this.state = STATE_RUNNABLE; - } - } else { - packet = null; - } - return this.task.run(packet); -}; - -/** - * Adds a packet to the worklist of this block's task, marks this as runnable if - * necessary, and returns the next runnable object to run (the one - * with the highest priority). - */ -TaskControlBlock.prototype.checkPriorityAdd = function (task, packet) { - if (this.queue == null) { - this.queue = packet; - this.markAsRunnable(); - if (this.priority > task.priority) return this; - } else { - this.queue = packet.addTo(this.queue); - } - return task; -}; - -TaskControlBlock.prototype.toString = function () { - return "tcb { " + this.task + "@" + this.state + " }"; +type Task = { + run(packet: Packet | null): TaskControlBlock | null; + toString(): string; }; /** * An idle task doesn't do any work itself but cycles control between the two * device tasks. - * @param {Scheduler} scheduler the scheduler that manages this task - * @param {int} v1 a seed value that controls how the device tasks are scheduled - * @param {int} count the number of times this task should be scheduled - * @constructor */ -function IdleTask(scheduler, v1, count) { - this.scheduler = scheduler; - this.v1 = v1; - this.count = count; -} +class IdleTask implements Task { + scheduler: Scheduler; + v1: number; + count: number; -IdleTask.prototype.run = function (packet) { - this.count--; - if (this.count == 0) return this.scheduler.holdCurrent(); - if ((this.v1 & 1) == 0) { - this.v1 = this.v1 >> 1; - return this.scheduler.release(ID_DEVICE_A); - } else { - this.v1 = (this.v1 >> 1) ^ 0xD008; - return this.scheduler.release(ID_DEVICE_B); + /** + * @param {Scheduler} scheduler the scheduler that manages this task + * @param {int} v1 a seed value that controls how the device tasks are scheduled + * @param {int} count the number of times this task should be scheduled + */ + constructor(scheduler: Scheduler, v1: number, count: number) { + this.scheduler = scheduler; + this.v1 = v1; + this.count = count; } -}; -IdleTask.prototype.toString = function () { - return "IdleTask"; -}; + run(_packet: Packet | null) { + this.count--; + if (this.count == 0) return this.scheduler.holdCurrent(); + if ((this.v1 & 1) == 0) { + this.v1 = this.v1 >> 1; + return this.scheduler.release(4 /* ID_DEVICE_A */); + } else { + this.v1 = (this.v1 >> 1) ^ 0xD008; + return this.scheduler.release(5 /* ID_DEVICE_B */); + } + } + + toString() { + return "IdleTask"; + } +} /** * A task that suspends itself after each time it has been run to simulate * waiting for data from an external device. - * @param {Scheduler} scheduler the scheduler that manages this task - * @constructor */ -function DeviceTask(scheduler) { - this.scheduler = scheduler; - this.v1 = null; -} +class DeviceTask implements Task { + scheduler: Scheduler; + v1: Packet | null; -DeviceTask.prototype.run = function (packet) { - if (packet == null) { - if (this.v1 == null) return this.scheduler.suspendCurrent(); - var v = this.v1; + /** + * @param {Scheduler} scheduler the scheduler that manages this task + * @constructor + */ + constructor(scheduler: Scheduler) { + this.scheduler = scheduler; this.v1 = null; - return this.scheduler.queue(v); - } else { - this.v1 = packet; - return this.scheduler.holdCurrent(); } -}; -DeviceTask.prototype.toString = function () { - return "DeviceTask"; -}; + run(packet: Packet | null) { + if (packet == null) { + if (this.v1 == null) return this.scheduler.suspendCurrent(); + var v = this.v1; + this.v1 = null; + return this.scheduler.queue(v); + } else { + this.v1 = packet; + return this.scheduler.holdCurrent(); + } + } + + toString() { + return "DeviceTask"; + } +} /** * A task that manipulates work packets. - * @param {Scheduler} scheduler the scheduler that manages this task - * @param {int} v1 a seed used to specify how work packets are manipulated - * @param {int} v2 another seed used to specify how work packets are manipulated - * @constructor */ -function WorkerTask(scheduler, v1, v2) { - this.scheduler = scheduler; - this.v1 = v1; - this.v2 = v2; -} +class WorkerTask implements Task { + scheduler: Scheduler; + v1: number; + v2: number; -WorkerTask.prototype.run = function (packet) { - if (packet == null) { - return this.scheduler.suspendCurrent(); - } else { - if (this.v1 == ID_HANDLER_A) { - this.v1 = ID_HANDLER_B; - } else { - this.v1 = ID_HANDLER_A; - } - packet.id = this.v1; - packet.a1 = 0; - for (var i = 0; i < DATA_SIZE; i++) { - this.v2++; - if (this.v2 > 26) this.v2 = 1; - packet.a2[i] = this.v2; - } - return this.scheduler.queue(packet); + /** + * @param {Scheduler} scheduler the scheduler that manages this task + * @param {int} v1 a seed used to specify how work packets are manipulated + * @param {int} v2 another seed used to specify how work packets are manipulated + * @constructor + */ + constructor(scheduler: Scheduler, v1: number, v2: number) { + this.scheduler = scheduler; + this.v1 = v1; + this.v2 = v2; } -}; -WorkerTask.prototype.toString = function () { - return "WorkerTask"; -}; + run(packet: Packet | null) { + if (packet == null) { + return this.scheduler.suspendCurrent(); + } else { + if (this.v1 == 2 /* ID_HANDLER_A */) { + this.v1 = 3 /* ID_HANDLER_B */; + } else { + this.v1 = 2 /* ID_HANDLER_A */; + } + packet.id = this.v1; + packet.a1 = 0; + for (var i = 0; i < 4 /* DATA_SIZE */; i++) { + this.v2++; + if (this.v2 > 26) this.v2 = 1; + packet.a2[i] = this.v2; + } + return this.scheduler.queue(packet); + } + } + + toString() { + return "WorkerTask"; + } +} /** * A task that manipulates work packets and then suspends itself. - * @param {Scheduler} scheduler the scheduler that manages this task - * @constructor */ -function HandlerTask(scheduler) { - this.scheduler = scheduler; - this.v1 = null; - this.v2 = null; -} +class HandlerTask { + scheduler: Scheduler; + v1: Packet | null; + v2: Packet | null; -HandlerTask.prototype.run = function (packet) { - if (packet != null) { - if (packet.kind == KIND_WORK) { - this.v1 = packet.addTo(this.v1); - } else { - this.v2 = packet.addTo(this.v2); - } + /** + * @param {Scheduler} scheduler the scheduler that manages this task + * @constructor + */ + constructor(scheduler: Scheduler) { + this.scheduler = scheduler; + this.v1 = null; + this.v2 = null; } - if (this.v1 != null) { - var count = this.v1.a1; - var v; - if (count < DATA_SIZE) { - if (this.v2 != null) { - v = this.v2; - this.v2 = this.v2.link; - v.a1 = this.v1.a2[count]; - this.v1.a1 = count + 1; + + run(packet: Packet | null) { + if (packet != null) { + if (packet.kind == 1 /* KIND_WORK */) { + this.v1 = packet.addTo(this.v1); + } else { + this.v2 = packet.addTo(this.v2); + } + } + if (this.v1 != null) { + var count = this.v1.a1; + var v; + if (count < 4 /* DATA_SIZE */) { + if (this.v2 != null) { + v = this.v2; + this.v2 = this.v2.link; + v.a1 = this.v1.a2[count]; + this.v1.a1 = count + 1; + return this.scheduler.queue(v); + } + } else { + v = this.v1; + this.v1 = this.v1.link; return this.scheduler.queue(v); } - } else { - v = this.v1; - this.v1 = this.v1.link; - return this.scheduler.queue(v); } + return this.scheduler.suspendCurrent(); } - return this.scheduler.suspendCurrent(); -}; -HandlerTask.prototype.toString = function () { - return "HandlerTask"; -}; + toString() { + return "HandlerTask"; + } +} /* --- * * P a c k e t * --- */ +class Packet { + // var DATA_SIZE = 4; -var DATA_SIZE = 4; + /** + * A simple package of data that is manipulated by the tasks. The exact layout + * of the payload data carried by a packet is not importaint, and neither is the + * nature of the work performed on packets by the tasks. + * + * Besides carrying data, packets form linked lists and are hence used both as + * data and worklists. + * @param {Packet} link the tail of the linked list of packets + * @param {int} id an ID for this packet + * @param {int} kind the type of this packet + * @constructor + */ -/** - * A simple package of data that is manipulated by the tasks. The exact layout - * of the payload data carried by a packet is not importaint, and neither is the - * nature of the work performed on packets by the tasks. - * - * Besides carrying data, packets form linked lists and are hence used both as - * data and worklists. - * @param {Packet} link the tail of the linked list of packets - * @param {int} id an ID for this packet - * @param {int} kind the type of this packet - * @constructor - */ -function Packet(link, id, kind) { - this.link = link; - this.id = id; - this.kind = kind; - this.a1 = 0; - this.a2 = new Array(DATA_SIZE); + link: Packet | null; + id: number | null; + kind: number; + a1: number; + a2: number[]; + + constructor(link: Packet | null, id: number, kind: number) { + this.link = link; + this.id = id; + this.kind = kind; + this.a1 = 0; + this.a2 = new Array(4 /* DATA_SIZE */); + } + + /** + * Add this packet to the end of a worklist, and return the worklist. + * @param {Packet} queue the worklist to add this packet to + */ + addTo(queue: Packet | null) { + this.link = null; + if (queue == null) return this; + var peek, next = queue; + while ((peek = next.link) != null) { + next = peek; + } + next.link = this; + return queue; + } + + toString() { + return "Packet"; + } } -/** - * Add this packet to the end of a worklist, and return the worklist. - * @param {Packet} queue the worklist to add this packet to - */ -Packet.prototype.addTo = function (queue) { - this.link = null; - if (queue == null) return this; - var peek, next = queue; - while ((peek = next.link) != null) { - next = peek; - } - next.link = this; - return queue; -}; - -Packet.prototype.toString = function () { - return "Packet"; -}; +runRichards();