Bug 1041537 - Prevent ContentSearch from leaking the browser if it's still processing a message while the test suite shuts down r=adw

This commit is contained in:
Tim Taubert 2014-08-21 11:18:54 +02:00
parent 2fbc0da862
commit 576d19c572
2 changed files with 52 additions and 30 deletions

View File

@ -81,7 +81,7 @@ this.ContentSearch = {
// them immediately, which would result in non-FIFO responses due to the
// asynchrononicity added by converting image data URIs to ArrayBuffers.
_eventQueue: [],
_currentEvent: null,
_currentEventPromise: null,
// This is used to handle search suggestions. It maps xul:browsers to objects
// { controller, previousFormHistoryResult }. See _onMessageGetSuggestions.
@ -94,6 +94,16 @@ this.ContentSearch = {
Services.obs.addObserver(this, "browser-search-engine-modified", false);
},
destroy: function () {
Cc["@mozilla.org/globalmessagemanager;1"].
getService(Ci.nsIMessageListenerManager).
removeMessageListener(INBOUND_MESSAGE, this);
Services.obs.removeObserver(this, "browser-search-engine-modified");
this._eventQueue.length = 0;
return Promise.resolve(this._currentEventPromise);
},
/**
* Focuses the search input in the page with the given message manager.
* @param messageManager
@ -141,22 +151,24 @@ this.ContentSearch = {
}
},
_processEventQueue: Task.async(function* () {
if (this._currentEvent || !this._eventQueue.length) {
_processEventQueue: function () {
if (this._currentEventPromise || !this._eventQueue.length) {
return;
}
this._currentEvent = this._eventQueue.shift();
try {
yield this["_on" + this._currentEvent.type](this._currentEvent.data);
}
catch (err) {
Cu.reportError(err);
}
finally {
this._currentEvent = null;
this._processEventQueue();
}
}),
let event = this._eventQueue.shift();
return this._currentEventPromise = Task.spawn(function* () {
try {
yield this["_on" + event.type](event.data);
} catch (err) {
Cu.reportError(err);
} finally {
this._currentEventPromise = null;
this._processEventQueue();
}
}.bind(this));
},
_onMessage: Task.async(function* (msg) {
let methodName = "_onMessage" + msg.data.type;

View File

@ -16,10 +16,13 @@ XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BrowserNewTabPreloader",
"resource:///modules/BrowserNewTabPreloader.jsm", "BrowserNewTabPreloader");
"resource:///modules/BrowserNewTabPreloader.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CustomizationTabPreloader",
"resource:///modules/CustomizationTabPreloader.jsm", "CustomizationTabPreloader");
"resource:///modules/CustomizationTabPreloader.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
"resource:///modules/ContentSearch.jsm");
const SIMPLETEST_OVERRIDES =
["ok", "is", "isnot", "ise", "todo", "todo_is", "todo_isnot", "info", "expectAssertions"];
@ -455,6 +458,8 @@ Tester.prototype = {
// is invoked to start the tests.
this.waitForWindowsState((function () {
if (this.done) {
let promise = Promise.resolve();
// Uninitialize a few things explicitly so that they can clean up
// frames and browser intentionally kept alive until shutdown to
// eliminate false positives.
@ -484,6 +489,9 @@ Tester.prototype = {
SocialFlyout.unload();
SocialShare.uninit();
TabView.uninit();
// Destroying ContentSearch is asynchronous.
promise = ContentSearch.destroy();
}
// Schedule GC and CC runs before finishing in order to detect
@ -515,20 +523,22 @@ Tester.prototype = {
}
};
checkForLeakedGlobalWindows(aResults => {
if (aResults.length == 0) {
this.finish();
return;
}
// After the first check, if there are reported leaked windows, sleep
// for a while, to allow off-main-thread work to complete and free up
// main-thread objects. Then check again.
setTimeout(() => {
checkForLeakedGlobalWindows(aResults => {
reportLeaks(aResults);
promise.then(() => {
checkForLeakedGlobalWindows(aResults => {
if (aResults.length == 0) {
this.finish();
});
}, 1000);
return;
}
// After the first check, if there are reported leaked windows, sleep
// for a while, to allow off-main-thread work to complete and free up
// main-thread objects. Then check again.
setTimeout(() => {
checkForLeakedGlobalWindows(aResults => {
reportLeaks(aResults);
this.finish();
});
}, 1000);
});
});
return;