Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Simple (cooperative) processes with the Scheduler
/**
* The simplest processes (cooperative tasks) with Scheduler
* (sort of Erlang's processes but without messages yet)
* See also: http://www.dabeaz.com/coroutines/index.html
*
* Deps: JS 1.7 with generators (yield)
*
* by Dmitry Soshnikov <dmitry.soshnikov@gmail.com>
* MIT Style License
*/
var Scheduler = (function initScheduler() {
var
/**
* run queue; processes
* ready to be executed
*/
runQueue = [],
/**
* processes map -- all
* currently alive processes
*/
processes = {},
/**
* to track count of
* alive processes
*/
processesCount = 0,
/**
* Autoinc process id, which is
* assigned to newborn process
*/
pid = 1;
return {
/**
* Currently running process,
* used in self() function
*/
runningProcess: null,
/**
* Sheduling is just putting a
* process to the run queue; it will be
* executed on next iteration of the handle loop
*/
schedule: function (process) {
runQueue.push(process);
},
/**
* Creates new process and
* automatically schedules it
*/
spawn: function (processLoop) {
var process = typeof processLoop == "function" ? processLoop() : processLoop;
process.pid = pid++;
processes[process.pid] = process;
processesCount++;
console.log("* Spawning new process with pid #" + process.pid);
this.schedule(process);
return process.pid;
},
/**
* Terminates a process by pid
* or the process itself parameter
*/
terminate: function (process) {
var pid = typeof process == "number" ? process : process.pid;
console.log("* Process #" + pid + " is terminated");
delete processes[pid];
processesCount--;
return pid;
},
/**
* Main scheduling loop: simply retrive a current process
* from the run queue, execute it, and schedule back
*/
handleLoop: function () {
console.log("* Scheduler loop started");
while (processesCount) {
try {
// get the next process in the run queue
var process = runQueue.shift();
// if there is something
if (process) {
// then run it
Scheduler.runningProcess = process;
process.next(); // execute the next "reductions" part (upto the next "yield" statement inside)
// and schedule back for next iteration
this.schedule(process);
}
} catch (e if (e instanceof StopIteration)) {
// if the process finishes,
// just remove it from the prcesses map
this.terminate(process);
}
}
console.log("* Scheduler loop stopped");
}
};
})();
// creates new process
function spawn(process) {
return Scheduler.spawn(process);
}
// helper function to get
// the pid of currently running process
function self() {
return Scheduler.runningProcess.pid;
}
// spawn 3 processes
for (var k = 3; k--;) {
spawn(function () {
console.log("Process #" + self() + " first entry");
yield;
console.log("Process #" + self() + " second entry");
});
}
// start main scheduling loop
Scheduler.handleLoop();
// Results:
// * Spawning new process with pid #1
// * Spawning new process with pid #2
// * Spawning new process with pid #3
// * Scheduler loop started
// Process #1 first entry
// Process #2 first entry
// Process #3 first entry
// Process #1 second entry
// * Process #1 is terminated
// Process #2 second entry
// * Process #2 is terminated
// Process #3 second entry
// * Process #3 is terminated
// * Scheduler loop stopped
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.