Skip to content

Commit

Permalink
Implementing web worker like wrapper around nsIThreadManager (inspire…
Browse files Browse the repository at this point in the history
…d by kriszyp)
  • Loading branch information
Gozala committed Oct 15, 2009
1 parent c977c75 commit dfe6465
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 0 deletions.
13 changes: 13 additions & 0 deletions lib/worker-engine.js
@@ -0,0 +1,13 @@
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;

var fs = require("file");

exports.createEnvironment = function createEnvironment() {
var workerGlobal = Cu.Sandbox(Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal));
var bootstrapPath = system.enginePrefix + "/bootstrap.js";
Cu.evalInSandbox(fs.read(bootstrapPath), workerGlobal, "1.8", bootstrapPath, 0);
return workerGlobal;
};

90 changes: 90 additions & 0 deletions lib/worker.js
@@ -0,0 +1,90 @@
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const ThreadManager = Cc["@mozilla.org/thread-manager;1"].getService();

function Message(trigger) {
this.trigger = trigger;
}
Message.prototype = {
QueryInterface: function(iid) {
if (iid.equals(Ci.nsIRunnable) || iid.equals(Ci.nsISupports)) return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
run: function() {
this.trigger();
}
};

var workerEngine = require("worker-engine");
var Worker = exports.Worker = function Worker(scriptName) {
var main = ThreadManager.mainThread;
return createWorker(scriptName, function(thread, global) {
var worker = createPort(main, global);
createPort(thread, worker, global);
return worker;
});
};

function createPort(thread, target, port) {
target.onmessage = true; // give it something to feature detect off of
port = port || {};
port.postMessage = function(message) {
try {
thread.dispatch(new Message(function() {
var event = {
//when is supposed to be the target, and when the ports? The spec is confusing
target: target,
ports: [target],
data: message.toString(),
}
if (typeof target.onmessage == "function") target.onmessage(event);
}), thread.DISPATCH_NORMAL);
} catch(e) {
if (typeof target.onerror == "function") target.onerror(e);
else Components.utils.reportError(e);
}
};
port.postData = function(message) {
try {
thread.dispatch(new Message(function() {
var event = {
ports: [target],
// this can be optimized to be much faster
data: target.JSON.parse(JSON.stringify(message)),
}
if (typeof target.ondata == "function") target.ondata(event);
}), thread.DISPATCH_NORMAL);
} catch(e) {
if (typeof target.onerror == "function") target.onerror(e);
else Components.utils.reportError(e);
}
};
return port;
};


function createWorker(scriptName, setup) {
var thread = ThreadManager.newThread(0);
var workerGlobal = workerEngine.createEnvironment();

// add the module lookup paths from our environment
var paths = workerGlobal.require.paths;
paths.splice(0, paths.length);
paths.push.apply(paths, require.paths);

// calback for dedicated and shared workers to do their thing
var worker = setup(thread, workerGlobal);
worker.terminate = function() {
thread.shutdown();
};
// there must be one and only one shared worker map amongst all workers
// workerGlobal.require("system").__sharedWorkers__ = system.__sharedWorkers__;

thread.dispatch(new Message(function() {
workerGlobal.require(scriptName);
}), thread.DISPATCH_NORMAL);
return worker;
};


4 changes: 4 additions & 0 deletions tests/all-tests.js
@@ -0,0 +1,4 @@
exports.testWorker = require("./test-worker");
if (require.main === module.id)
require("os").exit(require("test/runner").run(exports));

11 changes: 11 additions & 0 deletions tests/test-worker.js
@@ -0,0 +1,11 @@
var assert = require("test/assert");
var Worker = require("worker").Worker;

exports["test - demo"] = function() {
assert.isEqual(1, 1);
};


if (module.id == require.main)
require('os').exit(require('test/runner').run(exports));

9 changes: 9 additions & 0 deletions tests/thread.js
@@ -0,0 +1,9 @@
var fs = require("file");
onmessage = function(event) {
var n = parseInt(event.data);

for (var i = 1; i < n; i++) {
postMessage(i);
}
};

0 comments on commit dfe6465

Please sign in to comment.