0

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
This commit is contained in:
darin@chromium.org
2008-09-25 21:35:10 +00:00
parent 5f715e9411
commit 7e2fa03804
4 changed files with 61 additions and 28 deletions

@ -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) {}

@ -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());

@ -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() {

@ -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_