| Index: chrome/browser/ui/browser.cc
|
| diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
|
| index 3ba24b0440137eafbf740ed5a61c4de755860d99..32d5cc11b43f8300d4504ad3c1d0f8249b78cdb9 100644
|
| --- a/chrome/browser/ui/browser.cc
|
| +++ b/chrome/browser/ui/browser.cc
|
| @@ -2837,7 +2837,7 @@ void Browser::CloseContents(TabContents* source) {
|
| // waiting for unload to fire. Don't actually try to close the tab as it
|
| // will go down the slow shutdown path instead of the fast path of killing
|
| // all the renderer processes.
|
| - ClearUnloadState(source);
|
| + ClearUnloadState(source, true);
|
| return;
|
| }
|
|
|
| @@ -3198,12 +3198,10 @@ void Browser::Observe(NotificationType type,
|
| switch (type.value) {
|
| case NotificationType::TAB_CONTENTS_DISCONNECTED:
|
| if (is_attempting_to_close_browser_) {
|
| - // Need to do this asynchronously as it will close the tab, which is
|
| - // currently on the call stack above us.
|
| - MessageLoop::current()->PostTask(
|
| - FROM_HERE,
|
| - method_factory_.NewRunnableMethod(&Browser::ClearUnloadState,
|
| - Source<TabContents>(source).ptr()));
|
| + // Pass in false so that we delay processing. We need to delay the
|
| + // processing as it may close the tab, which is currently on the call
|
| + // stack above us.
|
| + ClearUnloadState(Source<TabContents>(source).ptr(), false);
|
| }
|
| break;
|
|
|
| @@ -3842,7 +3840,12 @@ void Browser::SyncHistoryWithTabs(int index) {
|
| // Browser, OnBeforeUnload handling (private):
|
|
|
| void Browser::ProcessPendingTabs() {
|
| - DCHECK(is_attempting_to_close_browser_);
|
| + if (!is_attempting_to_close_browser_) {
|
| + // Because we might invoke this after a delay it's possible for the value of
|
| + // is_attempting_to_close_browser_ to have changed since we scheduled the
|
| + // task.
|
| + return;
|
| + }
|
|
|
| if (HasCompletedUnloadProcessing()) {
|
| // We've finished all the unload events and can proceed to close the
|
| @@ -3860,7 +3863,7 @@ void Browser::ProcessPendingTabs() {
|
| if (tab->render_view_host()) {
|
| tab->render_view_host()->FirePageBeforeUnload(false);
|
| } else {
|
| - ClearUnloadState(tab);
|
| + ClearUnloadState(tab, true);
|
| }
|
| } else if (!tabs_needing_unload_fired_.empty()) {
|
| // We've finished firing all beforeunload events and can proceed with unload
|
| @@ -3877,7 +3880,7 @@ void Browser::ProcessPendingTabs() {
|
| if (tab->render_view_host()) {
|
| tab->render_view_host()->ClosePage(false, -1, -1);
|
| } else {
|
| - ClearUnloadState(tab);
|
| + ClearUnloadState(tab, true);
|
| }
|
| } else {
|
| NOTREACHED();
|
| @@ -3917,18 +3920,23 @@ bool Browser::RemoveFromSet(UnloadListenerSet* set, TabContents* tab) {
|
| return false;
|
| }
|
|
|
| -void Browser::ClearUnloadState(TabContents* tab) {
|
| +void Browser::ClearUnloadState(TabContents* tab, bool process_now) {
|
| // Closing of browser could be canceled (via IsClosingPermitted) between the
|
| // time when request was initiated and when this method is called, so check
|
| // for is_attempting_to_close_browser_ flag before proceeding.
|
| if (is_attempting_to_close_browser_) {
|
| RemoveFromSet(&tabs_needing_before_unload_fired_, tab);
|
| RemoveFromSet(&tabs_needing_unload_fired_, tab);
|
| - ProcessPendingTabs();
|
| + if (process_now) {
|
| + ProcessPendingTabs();
|
| + } else {
|
| + MessageLoop::current()->PostTask(
|
| + FROM_HERE,
|
| + method_factory_.NewRunnableMethod(&Browser::ProcessPendingTabs));
|
| + }
|
| }
|
| }
|
|
|
| -
|
| ///////////////////////////////////////////////////////////////////////////////
|
| // Browser, In-progress download termination handling (private):
|
|
|
| @@ -4087,6 +4095,14 @@ void Browser::TabDetachedAtImpl(TabContentsWrapper* contents, int index,
|
| find_bar_controller_->ChangeTabContents(NULL);
|
| }
|
|
|
| + if (is_attempting_to_close_browser_) {
|
| + // If this is the last tab with unload handlers, then ProcessPendingTabs
|
| + // would call back into the TabStripModel (which is invoking this method on
|
| + // us). Avoid that by passing in false so that the call to
|
| + // ProcessPendingTabs is delayed.
|
| + ClearUnloadState(contents->tab_contents(), false);
|
| + }
|
| +
|
| registrar_.Remove(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
|
| Source<TabContentsWrapper>(contents));
|
| }
|
|
|