Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions src/Process.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,21 @@ const { SchedulerInterrupt } = require('./constants/index');
// randomly determined.
class Process {
constructor(pid, cpuTimeNeeded=null, blocking=false) {
this._pid = pid;
this.queue = null;
this.cpuTimeNeeded = (cpuTimeNeeded !== null) ? cpuTimeNeeded : Math.round(Math.random() * 1000);
this._pid = pid; // means each prcocess/ process id
this.queue = null; // has a queue attached to it
this.cpuTimeNeeded = (cpuTimeNeeded !== null) ? cpuTimeNeeded : Math.round(Math.random() * 1000); // time needed the process needs to execute
this.blockingTimeNeeded = blocking ? Math.round(Math.random() * 100) : 0;
// A bool representing whether this process was toggled from blocking to non-blocking or vice versa
this.stateChanged = false;
this.stateChanged = false; // toggle between block and non-block state
}

setParentQueue(queue) {
this.queue = queue; // setting parent queue to queue

}

isFinished() {
return this.cpuTimeNeeded === 0 && this.blockingTimeNeeded === 0; // means done/finished if there are no more processes in the cpu queue or blocking queue

}

Expand All @@ -28,32 +30,50 @@ class Process {
// If blocking time is needed by this process, move it to the blocking queue
// by emitting the appropriate interrupt
// Make sure the `stateChanged` flag is toggled appropriately

executeProcess(time) {

this.stateChanged = false;
if (this.blockingTimeNeeded === 0) { // no blocking time is needed by the process
this.cpuTimeNeeded -= time; // decrement cpu time by the input time
this.cpuTimeNeeded = this.cpuTimeNeeded > 0 ? this.cpuTimeNeeded: 0; // if blocking time is needed as stated by blockingTimeNeeded > 0; if it time needes is 0 or a negative value, set it to 0
} else {
this.queue.emitInterrupt(this, SchedulerInterrupt.PROCESS_BLOCKED); // call interrupt function and move to Blocking/Blocked queue
this.stateChanged = true; // toggle state to true
}
}

// If this process requires blocking time, decrement the amount of blocking
// time it needs by the input time
// Once it no longer needs to perform any blocking execution, move it to the
// top running queue by emitting the appropriate interrupt
// Make sure the `stateChanged` flag is toggled appropriately
executeBlockingProcess(time) {

executeBlockingProcess(time) { // if process requires blocking time
this.blockingTimeNeeded -= time; // decrement blocking time by the input time
this.blockingTimeNeeded = this.blockingTimeNeeded > 0 ? this.blockingTimeNeeded: 0; // setting blockingTimeNeeded as either 0 or positive value

if (this.blockingTimeNeeded === 0) { // if blocking time/execution is finished/ no longer needed
this.queue.emitInterrupt(this, SchedulerInterrupt.PROCESS_READY); // call interrupt function and move it to top cpu queue
this.stateChanged = true; // toggle state change to true
}
}

// Returns this process's stateChanged property
isStateChanged() {
return this.stateChanged; // returning state was changed

}

get pid() {
return this._pid // return process id

}

// Private function used for testing; DO NOT MODIFY
_getParentQueue() {
return this.queue;
return this.queue;
}
}

module.exports = Process;

63 changes: 42 additions & 21 deletions src/Queue.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,71 +4,92 @@ const { SchedulerInterrupt } = require('./constants/index');
// blocking or non-blocking process
class Queue {
constructor(scheduler, quantum, priorityLevel, queueType) {
this.processes = [];
this.processes = []; // an array for all processes
// The queue's priority level; the lower the number, the higher the priority
this.priorityLevel = priorityLevel;
this.priorityLevel = priorityLevel; // keeps track of the processes' priority levels
// The queue's parent scheduler
this.scheduler = scheduler;
this.scheduler = scheduler; // communicate directly with scheduler via interrrupts
// The queue's allotted time slice; each process in this queue is executed for this amount of time in total
// This may be done over multiple scheduler iterations
this.quantum = quantum;
this.quantum = quantum; // mirrors the function cpuTimeNeeded; a process is done when quantum clock hits this quantum
// A counter to keep track of how much time the queue has been executing so far
this.quantumClock = 0;
this.quantumClock = 0;
this.queueType = queueType;
}

// Enqueues the given process. Return the enqueue'd process
enqueue(process) {

enqueue(process) { // puts the item into the queue
process.setParentQueue(this); // set the parent queue to 'this' queue
this.processes.push(process); // use array push
return process; // return the result of the push
}

// Dequeues the next process in the queue. Return the dequeue'd process
dequeue() {

dequeue() { // removes the item from the queue FIFO
return this.processes.shift(); // use array shift
}

// Return the least-recently added process without removing it from the list of processes
peek() {

peek() { // gives the process a reference number; only dequeues the process once it's done or have to be moved to the next priority queue
return this.processes[0]; // 0 index references/points to the process that was recently added
}

isEmpty() {

isEmpty() {
return this.processes.length === 0; // to check if queue is empty
}

getPriorityLevel() {

return this.priorityLevel;
}

getQueueType() {

return this.queueType;
}

// Manages a process's execution for the given amount of time
// Processes that have had their states changed should not be affected
// Once a process has received the alloted time, it needs to be dequeue'd and
// then handled accordingly, depending on whether it has finished executing or not
manageTimeSlice(currentProcess, time) {

manageTimeSlice(currentProcess, time) { // manages and keeps track of how much time has elapsed; similar to the function executeProcess in Process.js
if (currentProcess.isStateChanged()) { // check if process is in the blocking queue or not
this.quantumClock = 0;
return;
}

this.quantumClock += time;
if (this.quantumClock >= this.quantum) { // check if process has used up its alloted time
this.quantumClock = 0; // reset the quantum clock to 0 for the next process
const process = this.dequeue(); // dequeue

if (!process.isFinished ()) { // if process is not finished
this.scheduler.handleInterrupt(this, process, SchedulerInterrupt.LOWER_PRIORITY); // call the interrupt function and move process to lower priority queue
}
}
}

// Execute the next non-blocking process (assuming this is a CPU queue)
// This method should call `manageTimeSlice` as well as execute the next running process
doCPUWork(time) {

const process = this.peek(); // peek process
process.executeProcess(time); // call execute process passing in input time/ time slice
this.manageTimeSlice(process, time); // call manage time slice to call the bookkeeping of the time
}

// Execute the next blocking process (assuming this is the blocking queue)
// This method should call `manageTimeSlice` as well as execute the next blocking process
doBlockingWork(time) {

const process = this.peek();
process.executeBlockingProcess(time);
this.manageTimeSlice(process, time);
}

// The queue's interrupt handler for notifying when a process needs to be moved to a different queue
// Should handle PROCESS_BLOCKED and PROCESS_READY interrupts
// The process also needs to be removed from the queue
emitInterrupt(source, interrupt) {

emitInterrupt(source, interrupt) { // takes the interrupt and the source process and pass them along to the scheduler
const sourceIndex = this.processes.indexOf(source); // get the index of the process of the queue
this.processes.splice(sourceIndex, 1); // array splice; remove from the queue it's in
this.scheduler.handleInterrupt(this, source, interrupt);
}
}

Expand Down
52 changes: 46 additions & 6 deletions src/Scheduler.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const Queue = require('./Queue');
const {
QueueType,
SchedulerInterrupt,
PRIORITY_LEVELS,
} = require('./constants/index');

Expand All @@ -9,7 +10,7 @@ const {
// for non-blocking processes
class Scheduler {
constructor() {
this.clock = Date.now();
this.clock = Date.now(); // log the time that the last iteration finished
this.blockingQueue = new Queue(this, 50, 0, QueueType.BLOCKING_QUEUE);
this.runningQueues = [];
// Initialize all the CPU running queues
Expand All @@ -23,23 +24,62 @@ class Scheduler {
// time from the clock property. Don't forget to update the clock property afterwards.
// On every iteration of the scheduler, if the blocking queue is not empty, blocking work
// should be done. Once the blocking work has been done, perform some CPU work in the same iteration.
run() {

run() { // represents the entire thing running
while (true) {
const time = Date.now();
const timeSlice = time - this.clock; // represents how much time from the last iteration has elapsed with the time right now/ current time
this.clock = time;

if (!this.blockingQueue.isEmpty()) { // if blocking queue is not empty
this.blockingQueue.doBlockingWork(timeSlice); // do blocking work with time slice/ input
}

for (let i = 0; i < PRIORITY_LEVELS; i++) {
const queue = this.runningQueues[i]; // grab the running queue
if (!queue.isEmpty()) { // if queue is not empty
queue.doCPUWork(timeSlice); //call do CPU work taking in time slice
break; // break
}
}

if (this.allQueuesEmpty()) { // checking if all queues are empty
console.log('Done!');
break;
}
}
}

allQueuesEmpty() {

return this.runningQueues.every((queue) => queue.isEmpty()) && this.blockingQueue.isEmpty(); // use every array method; takes in a call back on every element in the array of the running queue
}

addNewProcess(process) {

this.runningQueues[0].enqueue(process);
}

// The scheduler's interrupt handler that receives a queue, a process, and an interrupt string constant
// Should handle PROCESS_BLOCKED, PROCESS_READY, and LOWER_PRIORITY interrupts.
handleInterrupt(queue, process, interrupt) {

}
switch(interrupt) {
case SchedulerInterrupt.PROCESS_BLOCKED:
this.blockingQueue.enqueue(process);
break;
case SchedulerInterrupt.PROCESS_READY:
this.addNewProcess(process);
break;
case SchedulerInterrupt.LOWER_PRIORITY:
if (queue.getQueueType() === QueueType.CPU_QUEUE) {
const priorityLevel = Math.min(PRIORITY_LEVELS - 1, queue.getPriorityLevel() + 1);
this.runningQueues[priorityLevel].enqueue(process);
} else {
this.blockingQueue.enqueue(process);
}
break;
default:
break;
}
}

// Private function used for testing; DO NOT MODIFY
_getCPUQueue(priorityLevel) {
Expand Down
Loading