Bug 852847 - Part 4: Fix a child-process shutdown leak around nested event loops. r=smaug

This also fixes a non-shutdown leak which occurs if you remove an
<iframe mozbrowser> from the DOM while it's processing an alert().
This commit is contained in:
Justin Lebar 2013-04-29 14:19:19 -04:00
parent 71ea5cad0e
commit 3894d095f8

View File

@ -103,6 +103,8 @@ BrowserElementChild.prototype = {
// Counter of contextmenu events fired
this._ctxCounter = 0;
this._shuttingDown = false;
addEventListener('DOMTitleChanged',
this._titleChangedHandler.bind(this),
/* useCapture = */ true,
@ -113,6 +115,16 @@ BrowserElementChild.prototype = {
/* useCapture = */ true,
/* wantsUntrusted = */ false);
// This listens to unload events from our message manager, but /not/ from
// the |content| window. That's because the window's unload event doesn't
// bubble, and we're not using a capturing listener. If we'd used
// useCapture == true, we /would/ hear unload events from the window, which
// is not what we want!
addEventListener('unload',
this._unloadHandler.bind(this),
/* useCapture = */ false,
/* wantsUntrusted = */ false);
// Registers a MozAfterPaint handler for the very first paint.
this._addMozAfterPaintHandler(function () {
sendAsyncMsg('firstpaint');
@ -185,6 +197,10 @@ BrowserElementChild.prototype = {
Services.obs.addObserver(this,
'ask-parent-to-rollback-fullscreen',
/* ownsWeak = */ true);
Services.obs.addObserver(this,
'xpcom-shutdown',
/* ownsWeak = */ true);
},
observe: function(subject, topic, data) {
@ -201,9 +217,20 @@ BrowserElementChild.prototype = {
case 'ask-parent-to-rollback-fullscreen':
sendAsyncMsg('rollback-fullscreen');
break;
case 'xpcom-shutdown':
this._shuttingDown = true;
break;
}
},
/**
* Called when our TabChildGlobal starts to die. This is not called when the
* page inside |content| unloads.
*/
_unloadHandler: function() {
this._shuttingDown = true;
},
_tryGetInnerWindowID: function(win) {
let utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
@ -275,9 +302,10 @@ BrowserElementChild.prototype = {
let thread = Services.tm.currentThread;
debug("Nested event loop - begin");
while (win.modalDepth == origModalDepth) {
while (win.modalDepth == origModalDepth && !this._shuttingDown) {
// Bail out of the loop if the inner window changed; that means the
// window navigated.
// window navigated. Bail out when we're shutting down because otherwise
// we'll leak our window.
if (this._tryGetInnerWindowID(win) !== innerWindowID) {
debug("_waitForResult: Inner window ID changed " +
"while in nested event loop.");