summaryrefslogtreecommitdiffstats
path: root/chrome/browser/render_view_host.cc
diff options
context:
space:
mode:
authorojan@google.com <ojan@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-29 23:32:47 +0000
committerojan@google.com <ojan@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-29 23:32:47 +0000
commitc82192d62ae8518837f448f9bbd9d0c93cd4af13 (patch)
tree795361f6bb6033caf55862386541c70e08b969be /chrome/browser/render_view_host.cc
parent9a2bba4ed0996b8bc9f8dab235ad83af3f155948 (diff)
downloadchromium_src-c82192d62ae8518837f448f9bbd9d0c93cd4af13.zip
chromium_src-c82192d62ae8518837f448f9bbd9d0c93cd4af13.tar.gz
chromium_src-c82192d62ae8518837f448f9bbd9d0c93cd4af13.tar.bz2
Fix not closing the browser with hung, crashed and interstitial tabs. Adds a 1 second hang monitor for the beforeunload/unload events to fire.
BUG=1296059 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/render_view_host.cc')
-rw-r--r--chrome/browser/render_view_host.cc46
1 files changed, 38 insertions, 8 deletions
diff --git a/chrome/browser/render_view_host.cc b/chrome/browser/render_view_host.cc
index 3080705..2b3ba62 100644
--- a/chrome/browser/render_view_host.cc
+++ b/chrome/browser/render_view_host.cc
@@ -74,6 +74,9 @@ void FilterURL(RendererSecurityPolicy* policy, int renderer_id, GURL* url) {
}
}
+// Delay to wait on closing the tab for a beforeunload/unload handler to fire.
+const int kUnloadTimeoutMS = 1000;
+
} // namespace
///////////////////////////////////////////////////////////////////////////////
@@ -107,7 +110,8 @@ RenderViewHost::RenderViewHost(SiteInstance* instance,
navigations_suspended_(false),
suspended_nav_message_(NULL),
run_modal_reply_msg_(NULL),
- has_unload_listener_(false) {
+ has_unload_listener_(false),
+ is_waiting_for_unload_ack_(false) {
DCHECK(instance_);
DCHECK(delegate_);
if (modal_dialog_event == NULL)
@@ -243,6 +247,11 @@ void RenderViewHost::SetNavigationsSuspended(bool suspend) {
void RenderViewHost::AttemptToClosePage(bool is_closing_browser) {
if (IsRenderViewLive()) {
+ // Start the hang monitor in case the renderer hangs in the beforeunload
+ // handler.
+ DCHECK(!is_waiting_for_unload_ack_);
+ is_waiting_for_unload_ack_ = true;
+ StartHangMonitorTimeout(kUnloadTimeoutMS);
Send(new ViewMsg_ShouldClose(routing_id_, is_closing_browser));
} else {
// This RenderViewHost doesn't have a live renderer, so just skip running
@@ -252,10 +261,13 @@ void RenderViewHost::AttemptToClosePage(bool is_closing_browser) {
}
void RenderViewHost::OnProceedWithClosePage(bool is_closing_browser) {
- Send(new ViewMsg_ClosePage(routing_id_,
- site_instance()->process_host_id(),
- routing_id(),
- is_closing_browser));
+ // Start the hang monitor in case the renderer hangs in the unload handler.
+ DCHECK(!is_waiting_for_unload_ack_);
+ is_waiting_for_unload_ack_ = true;
+ StartHangMonitorTimeout(kUnloadTimeoutMS);
+ ClosePage(site_instance()->process_host_id(),
+ routing_id(),
+ is_closing_browser);
}
// static
@@ -267,6 +279,10 @@ void RenderViewHost::ClosePageIgnoringUnloadEvents(int render_process_host_id,
if (!rvh)
return;
+ rvh->StopHangMonitorTimeout();
+ DCHECK(rvh->is_waiting_for_unload_ack_);
+ rvh->is_waiting_for_unload_ack_ = false;
+
// The RenderViewHost's delegate is a WebContents.
TabContents* tab = static_cast<WebContents*>(rvh->delegate());
rvh->UnloadListenerHasFired();
@@ -279,18 +295,20 @@ void RenderViewHost::ClosePageIgnoringUnloadEvents(int render_process_host_id,
}
void RenderViewHost::ClosePage(int new_render_process_host_id,
- int new_request_id) {
+ int new_request_id,
+ bool is_closing_browser) {
if (IsRenderViewLive()) {
Send(new ViewMsg_ClosePage(routing_id_,
new_render_process_host_id,
new_request_id,
- false)); // is_closing_browser
+ is_closing_browser));
} else {
// This RenderViewHost doesn't have a live renderer, so just skip closing
// the page. We must notify the ResourceDispatcherHost on the IO thread,
// which we will do through the RenderProcessHost's widget helper.
process()->CrossSiteClosePageACK(new_render_process_host_id,
- new_request_id);
+ new_request_id,
+ is_closing_browser);
}
}
@@ -1138,6 +1156,10 @@ void RenderViewHost::OnReceivedSerializedHtmlData(const GURL& frame_url,
void RenderViewHost::OnMsgShouldCloseACK(bool proceed,
bool is_closing_browser) {
+ StopHangMonitorTimeout();
+ DCHECK(is_waiting_for_unload_ack_);
+ is_waiting_for_unload_ack_ = false;
+
if (is_closing_browser) {
// The RenderViewHost's delegate is a WebContents.
TabContents* tab = static_cast<WebContents*>(delegate());
@@ -1155,6 +1177,14 @@ void RenderViewHost::OnUnloadListenerChanged(bool has_listener) {
}
void RenderViewHost::NotifyRendererUnresponsive() {
+ if (is_waiting_for_unload_ack_) {
+ // If the tab hangs in the beforeunload/unload handler there's really
+ // nothing we can do to recover. We can safely kill the process and the
+ // Browser will deal with the crash appropriately.
+ TerminateProcess(process()->process(), 0);
+ return;
+ }
+
// If the debugger is attached, we're going to be unresponsive anytime it's
// stopped at a breakpoint.
if (!debugger_attached_)