function Queue() { this.queue = []; } Queue.prototype.push_tail = function(msg) { this.queue.reverse(); this.queue.push(msg); this.queue.reverse(); } Queue.prototype.push_head = function(msg) { this.queue.push(msg); } Queue.prototype.pop = function() { return this.queue.pop(); } Queue.prototype.is_empty = function() { return this.queue.length == 0; } var current_process; var process_queue = new Queue(); var pid_count = 0; function Process(thunk) { var p = this; p.pid = ++pid_count; p.cont = function() { current_process = p; thunk(); current_process = undefined }; p.mailbox = new Queue(); p.blocked = false; } /* Send a message from the current process to another process. Reschedules itself if it was blocked waiting for a message. */ function send(process, msg) { if(process.blocked) { process.blocked = false; schedule(process); } process.mailbox.push_tail(msg); concede->(); } function block_if_no_messages(k) { if(current_process.mailbox.is_empty()) { var p = current_process; p.blocked = true; p.cont = function() { current_process = p; k(); current_process = undefined; } next_process(); } } function receive() { block_if_no_messages->(); var msg = current_process.mailbox.pop(); return msg; } function schedule(process) { process_queue.push_tail(process); start_scheduler(); } function unschedule() { return process_queue.pop(); } function concede(k) { var p = current_process; p.cont = function() { current_process = p; k(); current_process = undefined; } schedule(p); next_process(); } function sleep(ms,cont) { var s = 10; while(s < ms) { concede->(); s += 10; } } function start(processes) { for(var i = 0; i < processes.length; ++i) { process_queue.push_head(processes[i]); } start_scheduler(); } function spawn(func) { var p = new Process(func); start([p]); return p; } var scheduler_started = false; function start_scheduler() { if(!scheduler_started) { scheduler_started = true; while(!process_queue.is_empty()) { next_process(); } } scheduler_started = false; } function next_process() { var p = unschedule(); if(p) { var k = p.cont; if(k) { setTimeout(k, 10); } } }