summaryrefslogtreecommitdiffstats
path: root/chrome/browser/external_tab_container.cc
diff options
context:
space:
mode:
authorananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-03 21:38:08 +0000
committerananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-03 21:38:08 +0000
commite56e96f80ce491b23454a039ae5eba1a1c6ee3f9 (patch)
tree0cd3a2bb9352b35a7caff1287b310686776e2751 /chrome/browser/external_tab_container.cc
parent8c07fdb39d54c0bddcadc563a1d380ce56b3c9a5 (diff)
downloadchromium_src-e56e96f80ce491b23454a039ae5eba1a1c6ee3f9.zip
chromium_src-e56e96f80ce491b23454a039ae5eba1a1c6ee3f9.tar.gz
chromium_src-e56e96f80ce491b23454a039ae5eba1a1c6ee3f9.tar.bz2
The ExternalTabContainer enters a modal loop while waiting for the unload events on the tab to complete.
If multiple ChromeFrame tabs were closed together then we end up in a nested loop hierarchy. In this case the innermost message loop ends up dispatching the TabContents::Close method which then calls its delegate which is the ExternalTabContainer for the other ExternalTabs as well. As a result the outer loops never exit, which causes IE tabs to hang. Fix is to use a local global stack of ExternalTabContainers. If we receive a CloseContents call for any other container but the innermost one, we post it back to the loop. Bug=31853 Review URL: http://codereview.chromium.org/560034 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@38022 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/external_tab_container.cc')
-rw-r--r--chrome/browser/external_tab_container.cc27
1 files changed, 25 insertions, 2 deletions
diff --git a/chrome/browser/external_tab_container.cc b/chrome/browser/external_tab_container.cc
index e717490..6e89fcd 100644
--- a/chrome/browser/external_tab_container.cc
+++ b/chrome/browser/external_tab_container.cc
@@ -35,6 +35,8 @@
static const wchar_t kWindowObjectKey[] = L"ChromeWindowObject";
ExternalTabContainer::PendingTabs ExternalTabContainer::pending_tabs_;
+ExternalTabContainer* ExternalTabContainer::innermost_tab_for_unload_event_
+ = NULL;
ExternalTabContainer::ExternalTabContainer(
AutomationProvider* automation, AutomationResourceMessageFilter* filter)
@@ -164,12 +166,21 @@ void ExternalTabContainer::Uninitialize() {
registrar_.RemoveAll();
if (tab_contents_) {
+ waiting_for_unload_event_ = true;
if (Browser::RunUnloadEventsHelper(tab_contents_)) {
- waiting_for_unload_event_ = true;
+ // Maintain a local global stack of Externa;TabCotainers waiting for the
+ // unload event listeners to finish. We need this as we only want to
+ // handle the CloseContents call from the TabContents when the current
+ // ExternalTabContainers message loop is active. This ensures that nested
+ // ExternalTabContainer message loops terminate correctly.
+ ExternalTabContainer* current_tab = innermost_tab_for_unload_event_;
+ innermost_tab_for_unload_event_ = this;
MessageLoop::current()->Run();
- waiting_for_unload_event_ = false;
+ innermost_tab_for_unload_event_ = current_tab;
}
+ waiting_for_unload_event_ = false;
+
RenderViewHost* rvh = tab_contents_->render_view_host();
if (rvh && DevToolsManager::GetInstance()) {
DevToolsManager::GetInstance()->UnregisterDevToolsClientHostFor(rvh);
@@ -375,7 +386,19 @@ void ExternalTabContainer::LoadingStateChanged(TabContents* source) {
}
void ExternalTabContainer::CloseContents(TabContents* source) {
+ static const int kExternalTabCloseContentsDelayMS = 100;
+
if (waiting_for_unload_event_) {
+ // If we are not the innermost tab waiting for the unload event to return
+ // then don't handle this notification right away as we need the inner
+ // message loop to terminate.
+ if (this != innermost_tab_for_unload_event_) {
+ ChromeThread::PostDelayedTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &ExternalTabContainer::CloseContents,
+ source), kExternalTabCloseContentsDelayMS);
+ return;
+ }
MessageLoop::current()->Quit();
}
}