summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordarin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-25 21:35:10 +0000
committerdarin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-25 21:35:10 +0000
commit7e2fa03804bef4bff9c5bb941f2edf09b6d234c0 (patch)
tree535d81a14867f7b037bec19764bfaa56a53acd33
parent5f715e9411a0b4b8e207072fdbfad5160f5ad1e2 (diff)
downloadchromium_src-7e2fa03804bef4bff9c5bb941f2edf09b6d234c0.zip
chromium_src-7e2fa03804bef4bff9c5bb941f2edf09b6d234c0.tar.gz
chromium_src-7e2fa03804bef4bff9c5bb941f2edf09b6d234c0.tar.bz2
Stop spamming delayed tasks on each input event.
R=mbelshe BUG=2693 Review URL: http://codereview.chromium.org/4262 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2609 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/timer.h7
-rw-r--r--chrome/browser/render_view_host.cc8
-rw-r--r--chrome/browser/render_widget_host.cc43
-rw-r--r--chrome/browser/render_widget_host.h31
4 files changed, 61 insertions, 28 deletions
diff --git a/base/timer.h b/base/timer.h
index 32adbf1..5361130 100644
--- a/base/timer.h
+++ b/base/timer.h
@@ -66,6 +66,13 @@ class BaseTimer_Helper {
return delayed_task_ != NULL;
}
+ // Returns the current delay for this timer. May only call this method when
+ // the timer is running!
+ TimeDelta GetCurrentDelay() const {
+ DCHECK(IsRunning());
+ return delayed_task_->delay_;
+ }
+
protected:
BaseTimer_Helper() : delayed_task_(NULL) {}
diff --git a/chrome/browser/render_view_host.cc b/chrome/browser/render_view_host.cc
index 8c95e07..27b25c9 100644
--- a/chrome/browser/render_view_host.cc
+++ b/chrome/browser/render_view_host.cc
@@ -233,7 +233,7 @@ void RenderViewHost::FirePageBeforeUnload() {
// Start the hang monitor in case the renderer hangs in the beforeunload
// handler.
is_waiting_for_unload_ack_ = true;
- StartHangMonitorTimeout(kUnloadTimeoutMS);
+ StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS));
Send(new ViewMsg_ShouldClose(routing_id_));
} else {
// This RenderViewHost doesn't have a live renderer, so just skip running
@@ -245,7 +245,7 @@ void RenderViewHost::FirePageBeforeUnload() {
void RenderViewHost::FirePageUnload() {
// Start the hang monitor in case the renderer hangs in the unload handler.
is_waiting_for_unload_ack_ = true;
- StartHangMonitorTimeout(kUnloadTimeoutMS);
+ StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS));
ClosePage(site_instance()->process_host_id(),
routing_id());
}
@@ -487,7 +487,7 @@ void RenderViewHost::JavaScriptMessageBoxClosed(IPC::Message* reply_msg,
bool success,
const std::wstring& prompt) {
if (is_waiting_for_unload_ack_)
- StartHangMonitorTimeout(kUnloadTimeoutMS);
+ StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS));
if (--modal_dialog_count_ == 0)
ResetEvent(modal_dialog_event_.Get());
@@ -498,7 +498,7 @@ void RenderViewHost::JavaScriptMessageBoxClosed(IPC::Message* reply_msg,
void RenderViewHost::ModalHTMLDialogClosed(IPC::Message* reply_msg,
const std::string& json_retval) {
if (is_waiting_for_unload_ack_)
- StartHangMonitorTimeout(kUnloadTimeoutMS);
+ StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS));
if (--modal_dialog_count_ == 0)
ResetEvent(modal_dialog_event_.Get());
diff --git a/chrome/browser/render_widget_host.cc b/chrome/browser/render_widget_host.cc
index 34e9c26..449b194 100644
--- a/chrome/browser/render_widget_host.cc
+++ b/chrome/browser/render_widget_host.cc
@@ -273,7 +273,6 @@ RenderWidgetHost::RenderWidgetHost(RenderProcessHost* process, int routing_id)
is_hidden_(false),
suppress_view_updating_(false),
needs_repainting_on_restore_(false),
- hung_renderer_factory_(this),
is_unresponsive_(false),
view_being_painted_(false),
repaint_ack_pending_(false) {
@@ -630,7 +629,7 @@ void RenderWidgetHost::ForwardInputEvent(const WebInputEvent& input_event,
// any input event cancels a pending mouse move event
next_mouse_move_.reset();
- StartHangMonitorTimeout(kHungRendererDelayMs);
+ StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kHungRendererDelayMs));
}
void RenderWidgetHost::Shutdown() {
@@ -673,7 +672,19 @@ void RenderWidgetHost::Destroy() {
delete this;
}
-void RenderWidgetHost::RendererIsUnresponsive() {
+void RenderWidgetHost::CheckRendererIsUnresponsive() {
+ // If we received a call to StopHangMonitorTimeout.
+ if (time_when_considered_hung_.is_null())
+ return;
+
+ // If we have not waited long enough, then wait some more.
+ Time now = Time::Now();
+ if (now < time_when_considered_hung_) {
+ StartHangMonitorTimeout(time_when_considered_hung_ - now);
+ return;
+ }
+
+ // OK, looks like we have a hung renderer!
NotificationService::current()->Notify(NOTIFY_RENDERER_PROCESS_HANG,
Source<RenderWidgetHost>(this),
NotificationService::NoDetails());
@@ -788,19 +799,31 @@ void RenderWidgetHost::ScrollRect(HANDLE bitmap, const gfx::Rect& bitmap_rect,
}
void RenderWidgetHost::RestartHangMonitorTimeout() {
- hung_renderer_factory_.RevokeAll();
- StartHangMonitorTimeout(kHungRendererDelayMs);
+ StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kHungRendererDelayMs));
}
void RenderWidgetHost::StopHangMonitorTimeout() {
- hung_renderer_factory_.RevokeAll();
+ time_when_considered_hung_ = Time();
RendererIsResponsive();
+
+ // We do not bother to stop the hung_renderer_timer_ here in case it will be
+ // started again shortly, which happens to be the common use case.
}
-void RenderWidgetHost::StartHangMonitorTimeout(int delay) {
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- hung_renderer_factory_.NewRunnableMethod(
- &RenderWidgetHost::RendererIsUnresponsive), delay);
+void RenderWidgetHost::StartHangMonitorTimeout(TimeDelta delay) {
+ time_when_considered_hung_ = Time::Now() + delay;
+
+ // If we already have a timer that will expire at or before the given delay,
+ // then we have nothing more to do now.
+ if (hung_renderer_timer_.IsRunning() &&
+ hung_renderer_timer_.GetCurrentDelay() <= delay)
+ return;
+
+ // Either the timer is not yet running, or we need to adjust the timer to
+ // fire sooner.
+ hung_renderer_timer_.Stop();
+ hung_renderer_timer_.Start(delay, this,
+ &RenderWidgetHost::CheckRendererIsUnresponsive);
}
void RenderWidgetHost::RendererExited() {
diff --git a/chrome/browser/render_widget_host.h b/chrome/browser/render_widget_host.h
index 0db4dbd..fd542e7 100644
--- a/chrome/browser/render_widget_host.h
+++ b/chrome/browser/render_widget_host.h
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_RENDER_WIDGET_HOST_H__
-#define CHROME_BROWSER_RENDER_WIDGET_HOST_H__
+#ifndef CHROME_BROWSER_RENDER_WIDGET_HOST_H_
+#define CHROME_BROWSER_RENDER_WIDGET_HOST_H_
#include <windows.h>
-#include "base/task.h"
#include "base/gfx/size.h"
+#include "base/timer.h"
#include "chrome/common/ipc_channel.h"
namespace gfx {
@@ -180,11 +180,11 @@ class RenderWidgetHost : public IPC::Channel::Listener {
// javascript call.
virtual bool CanBlur() const { return true; }
- // Restart the active hang monitor timeout. Clears all existing timeouts
- // and starts with a new one.
- // This can be because the renderer has become active, the tab is being
- // hidden, or the user has chosen to wait some more to give the tab a chance
- // to become active and we don't want to display a warning too soon.
+ // Restart the active hang monitor timeout. Clears all existing timeouts and
+ // starts with a new one. This can be because the renderer has become
+ // active, the tab is being hidden, or the user has chosen to wait some more
+ // to give the tab a chance to become active and we don't want to display a
+ // warning too soon.
void RestartHangMonitorTimeout();
// Stops all existing hang monitor timeouts and assumes the renderer is
@@ -194,7 +194,7 @@ class RenderWidgetHost : public IPC::Channel::Listener {
// Starts a hang monitor timeout. If there's already a hang monitor timeout
// the new one will only fire if it has a shorter delay than the time
// left on the existing timeouts.
- void StartHangMonitorTimeout(int delay);
+ void StartHangMonitorTimeout(TimeDelta delay);
// Called when we receive a notification indicating that the renderer
// process has gone.
@@ -250,7 +250,7 @@ class RenderWidgetHost : public IPC::Channel::Listener {
// Callbacks for notification when the renderer becomes unresponsive to user
// input events, and subsequently responsive again. The delegate can use
// these notifications to show a warning.
- void RendererIsUnresponsive();
+ void CheckRendererIsUnresponsive();
virtual void NotifyRendererUnresponsive() {}
void RendererIsResponsive();
virtual void NotifyRendererResponsive() {}
@@ -298,8 +298,12 @@ class RenderWidgetHost : public IPC::Channel::Listener {
// itself, a paint message could already be in flight at that point.
bool needs_repainting_on_restore_;
- // The following factory is used to detect a hung renderer
- ScopedRunnableMethodFactory<RenderWidgetHost> hung_renderer_factory_;
+ // The following value indicates a time in the future when we would consider
+ // the renderer hung if it does not generate an appropriate response message.
+ Time time_when_considered_hung_;
+
+ // This timer runs to check if time_when_considered_hung_ has past.
+ base::OneShotTimer<RenderWidgetHost> hung_renderer_timer_;
// This is true if the renderer is currently unresponsive.
bool is_unresponsive_;
@@ -359,5 +363,4 @@ class RenderWidgetHost::PaintObserver {
virtual void RenderWidgetHostDidPaint(RenderWidgetHost* rwh) = 0;
};
-#endif // #ifndef CHROME_BROWSER_RENDER_WIDGET_HOST_H__
-
+#endif // #ifndef CHROME_BROWSER_RENDER_WIDGET_HOST_H_