Bug 801598 - Making SessionWorker use the now public PromiseWorker API. r=ttaubert

This commit is contained in:
David Rajchenbach-Teller 2014-07-01 05:26:00 +02:00
parent 181f4026b8
commit 84b432c9af
3 changed files with 33 additions and 79 deletions

View File

@ -33,7 +33,6 @@ const Cr = Components.results;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource://gre/modules/osfile/_PromiseWorker.jsm", this);
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/AsyncShutdown.jsm");
@ -193,13 +192,6 @@ let SessionFileInternal = {
}
},
/**
* The promise returned by the latest call to |write|.
* We use it to ensure that AsyncShutdown.profileBeforeChange cannot
* interrupt a call to |write|.
*/
_latestWrite: null,
/**
* |true| once we have decided to stop receiving write instructiosn
*/
@ -278,9 +270,17 @@ let SessionFileInternal = {
isFinalWrite = this._isClosed = true;
}
return this._latestWrite = Task.spawn(function* task() {
let deferredWritten = Promise.defer();
return Task.spawn(function* task() {
TelemetryStopwatch.start("FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS", refObj);
// Ensure that we can write sessionstore.js cleanly before the profile
// becomes unaccessible.
AsyncShutdown.profileBeforeChange.addBlocker(
"SessionFile: Finish writing Session Restore data",
deferredWritten.promise
);
try {
let performShutdownCleanup = isFinalWrite &&
!sessionStartup.isAutomaticRestoreEnabled();
@ -296,14 +296,18 @@ let SessionFileInternal = {
let msg = yield promise;
this._recordTelemetry(msg.telemetry);
if (msg.ok && msg.ok.upgradeBackup) {
if (msg.result.upgradeBackup) {
// We have just completed a backup-on-upgrade, store the information
// in preferences.
Services.prefs.setCharPref(PREF_UPGRADE_BACKUP, Services.appinfo.platformBuildID);
}
deferredWritten.resolve();
} catch (ex) {
TelemetryStopwatch.cancel("FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS", refObj);
console.error("Could not write session state file ", ex, ex.stack);
deferredWritten.reject(ex);
} finally {
AsyncShutdown.profileBeforeChange.removeBlocker(deferredWritten.promise);
}
if (isFinalWrite) {
@ -332,11 +336,3 @@ let SessionFileInternal = {
}
}
};
// Ensure that we can write sessionstore.js cleanly before the profile
// becomes unaccessible.
AsyncShutdown.profileBeforeChange.addBlocker(
"SessionFile: Finish writing the latest sessionstore.js",
function() {
return SessionFileInternal._latestWrite;
});

View File

@ -10,48 +10,24 @@
importScripts("resource://gre/modules/osfile.jsm");
let PromiseWorker = require("resource://gre/modules/workers/PromiseWorker.js");
let File = OS.File;
let Encoder = new TextEncoder();
let Decoder = new TextDecoder();
/**
* Communications with the controller.
*
* Accepts messages:
* {fun:function_name, args:array_of_arguments_or_null, id: custom_id}
*
* Sends messages:
* {ok: result, id: custom_id, telemetry: {}} /
* {fail: serialized_form_of_OS.File.Error, id: custom_id}
*/
self.onmessage = function (msg) {
let data = msg.data;
if (!(data.fun in Agent)) {
throw new Error("Cannot find method " + data.fun);
}
let result;
let id = data.id;
try {
result = Agent[data.fun].apply(Agent, data.args) || {};
} catch (ex if ex instanceof OS.File.Error) {
// Instances of OS.File.Error know how to serialize themselves
// (deserialization ensures that we end up with OS-specific
// instances of |OS.File.Error|)
self.postMessage({fail: OS.File.Error.toMsg(ex), id: id});
return;
}
// Other exceptions do not, and should be propagated through DOM's
// built-in mechanism for uncaught errors, although this mechanism
// may lose interesting information.
self.postMessage({
ok: result.result,
id: id,
telemetry: result.telemetry || {}
});
let worker = new PromiseWorker.AbstractWorker();
worker.dispatch = function(method, args = []) {
return Agent[method](...args);
};
worker.postMessage = function(result, ...transfers) {
self.postMessage(result, ...transfers);
};
worker.close = function() {
self.close();
};
self.addEventListener("message", msg => worker.handleMessage(msg));
// The various possible states

View File

@ -13,31 +13,13 @@ const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
Cu.import("resource://gre/modules/osfile/_PromiseWorker.jsm", this);
Cu.import("resource://gre/modules/PromiseWorker.jsm", this);
Cu.import("resource://gre/modules/osfile.jsm", this);
this.EXPORTED_SYMBOLS = ["SessionWorker"];
this.SessionWorker = (function () {
let worker = new PromiseWorker("resource:///modules/sessionstore/SessionWorker.js",
OS.Shared.LOG.bind("SessionWorker"));
return {
post: function post(...args) {
let promise = worker.post.apply(worker, args);
return promise.then(
null,
function onError(error) {
// Decode any serialized error
if (error instanceof PromiseWorker.WorkerError) {
throw OS.File.Error.fromMsg(error.data);
}
// Extract something meaningful from ErrorEvent
if (error instanceof ErrorEvent) {
throw new Error(error.message, error.filename, error.lineno);
}
throw error;
}
);
}
};
})();
this.SessionWorker = new BasePromiseWorker("resource:///modules/sessionstore/SessionWorker.js");
// As the Session Worker performs I/O, we can receive instances of
// OS.File.Error, so we need to install a decoder.
this.SessionWorker.ExceptionHandlers["OS.File.Error"] = OS.File.Error.fromMsg;