Bug 1072814 - Fix SessionFile.jsm to use new Promise() API r=yoric
authorTim Taubert <ttaubert@mozilla.com>
Thu, 25 Sep 2014 04:51:37 +0200
changeset 207465 fbcaa7a5505cc0d534e4e0448a974b7182605fc5
parent 207464 c4c40e8e2691b81e5e89306d9f0ccc41dce0a86e
child 207466 04ae87ed4a417b7f33bbd193cb04ec84fbf2f7d7
push id27555
push userryanvm@gmail.com
push dateFri, 26 Sep 2014 20:30:28 +0000
treeherderautoland@4ff52be673f6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersyoric
bugs1072814
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1072814 - Fix SessionFile.jsm to use new Promise() API r=yoric
browser/components/sessionstore/SessionFile.jsm
--- a/browser/components/sessionstore/SessionFile.jsm
+++ b/browser/components/sessionstore/SessionFile.jsm
@@ -260,69 +260,80 @@ let SessionFileInternal = {
       throw new Task.Result(msg.telemetry);
     }.bind(this));
   },
 
   write: function (aData) {
     if (this._isClosed) {
       return Promise.reject(new Error("SessionFile is closed"));
     }
-    let refObj = {};
 
     let isFinalWrite = false;
     if (Services.startup.shuttingDown) {
       // If shutdown has started, we will want to stop receiving
       // write instructions.
       isFinalWrite = this._isClosed = true;
     }
 
-    let deferredWritten = Promise.defer();
-    return Task.spawn(function* task() {
-      TelemetryStopwatch.start("FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS", refObj);
+    let refObj = {};
+    let name = "FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS";
 
-      // Ensure that we can write sessionstore.js cleanly before the profile
-      // becomes unaccessible.
-      AsyncShutdown.profileBeforeChange.addBlocker(
-        "SessionFile: Finish writing Session Restore data",
-        deferredWritten.promise
-      );
+    let promise = new Promise(resolve => {
+      // Start measuring main thread impact.
+      TelemetryStopwatch.start(name, refObj);
+
+      let performShutdownCleanup = isFinalWrite &&
+        !sessionStartup.isAutomaticRestoreEnabled();
+
+      let options = {isFinalWrite, performShutdownCleanup};
 
       try {
-        let performShutdownCleanup = isFinalWrite &&
-          !sessionStartup.isAutomaticRestoreEnabled();
-        let options = {
-          isFinalWrite: isFinalWrite,
-          performShutdownCleanup: performShutdownCleanup
-        };
-        let promise = SessionWorker.post("write", [aData, options]);
-        // At this point, we measure how long we stop the main thread
-        TelemetryStopwatch.finish("FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS", refObj);
+        resolve(SessionWorker.post("write", [aData, options]));
+      } finally {
+        // Record how long we stopped the main thread.
+        TelemetryStopwatch.finish(name, refObj);
+      }
+    });
 
-        // Now wait for the result and record how long the write took
-        let msg = yield promise;
-        this._recordTelemetry(msg.telemetry);
+    // Wait until the write is done.
+    promise = promise.then(msg => {
+      // Record how long the write took.
+      this._recordTelemetry(msg.telemetry);
 
-        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 (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);
       }
+    }, err => {
+      // Catch and report any errors.
+      TelemetryStopwatch.cancel(name, refObj);
+      console.error("Could not write session state file ", err, err.stack);
+      // By not doing anything special here we ensure that |promise| cannot
+      // be rejected anymore. The shutdown/cleanup code at the end of the
+      // function will thus always be executed.
+    });
+
+    // Ensure that we can write sessionstore.js cleanly before the profile
+    // becomes unaccessible.
+    AsyncShutdown.profileBeforeChange.addBlocker(
+      "SessionFile: Finish writing Session Restore data", promise);
+
+    // This code will always be executed because |promise| can't fail anymore.
+    // We ensured that by having a reject handler that reports the failure but
+    // doesn't forward the rejection.
+    return promise.then(() => {
+      // Remove the blocker, no matter if writing failed or not.
+      AsyncShutdown.profileBeforeChange.removeBlocker(promise);
 
       if (isFinalWrite) {
         Services.obs.notifyObservers(null, "sessionstore-final-state-write-complete", "");
       }
-    }.bind(this));
+    });
   },
 
   wipe: function () {
     return SessionWorker.post("wipe");
   },
 
   _recordTelemetry: function(telemetry) {
     for (let id of Object.keys(telemetry)){