Index: chrome/renderer/render_thread.cc |
=================================================================== |
--- chrome/renderer/render_thread.cc (revision 24223) |
+++ chrome/renderer/render_thread.cc (working copy) |
@@ -9,6 +9,7 @@ |
#include "base/command_line.h" |
#include "base/lazy_instance.h" |
+#include "base/logging.h" |
#include "base/shared_memory.h" |
#include "base/stats_table.h" |
#include "base/thread_local.h" |
@@ -58,6 +59,8 @@ |
namespace { |
static const unsigned int kCacheStatsDelayMS = 2000 /* milliseconds */; |
+static const double kInitialIdleHandlerDelayS = 1.0 /* seconds */; |
+ |
static base::LazyInstance<base::ThreadLocalPointer<RenderThread> > lazy_tls( |
base::LINKER_INITIALIZED); |
@@ -105,8 +108,11 @@ |
#endif |
plugin_refresh_allowed_ = true; |
- cache_stats_factory_.reset( |
- new ScopedRunnableMethodFactory<RenderThread>(this)); |
+ cache_stats_task_pending_ = false; |
+ widget_count_ = 0; |
+ hidden_widget_count_ = 0; |
+ idle_notification_delay_in_s_ = kInitialIdleHandlerDelayS; |
+ task_factory_.reset(new ScopedRunnableMethodFactory<RenderThread>(this)); |
visited_link_slave_.reset(new VisitedLinkSlave()); |
user_script_slave_.reset(new UserScriptSlave()); |
@@ -156,6 +162,30 @@ |
channel()->RemoveFilter(filter); |
} |
+void RenderThread::WidgetHidden() { |
+ DCHECK(hidden_widget_count_ <= widget_count_); |
+ hidden_widget_count_++ ; |
+ if (hidden_widget_count_ == widget_count_) { |
+ // Reset the delay. |
+ idle_notification_delay_in_s_ = kInitialIdleHandlerDelayS; |
+ |
+ // Schedule the IdleHandler to wakeup in a bit. |
+ MessageLoop::current()->PostDelayedTask(FROM_HERE, |
+ task_factory_->NewRunnableMethod(&RenderThread::IdleHandler), |
+ static_cast<int64>(floor(idle_notification_delay_in_s_)) * 1000); |
+ } |
+} |
+ |
+void RenderThread::WidgetRestored() { |
+ DCHECK(hidden_widget_count_ > 0); |
+ hidden_widget_count_--; |
+ |
+ // Note: we may have a timer pending to call the IdleHandler (see the |
+ // WidgetHidden() code). But we don't bother to cancel it as it is |
+ // benign and won't do anything if the tab is un-hidden when it is |
+ // called. |
+} |
+ |
void RenderThread::Resolve(const char* name, size_t length) { |
return dns_master_->Resolve(name, length); |
} |
@@ -316,15 +346,17 @@ |
WebCache::UsageStats stats; |
WebCache::getUsageStats(&stats); |
Send(new ViewHostMsg_UpdatedCacheStats(stats)); |
+ cache_stats_task_pending_ = false; |
} |
void RenderThread::InformHostOfCacheStatsLater() { |
// Rate limit informing the host of our cache stats. |
- if (!cache_stats_factory_->empty()) |
+ if (cache_stats_task_pending_) |
return; |
+ cache_stats_task_pending_ = true; |
MessageLoop::current()->PostDelayedTask(FROM_HERE, |
- cache_stats_factory_->NewRunnableMethod( |
+ task_factory_->NewRunnableMethod( |
&RenderThread::InformHostOfCacheStats), |
kCacheStatsDelayMS); |
} |
@@ -417,6 +449,31 @@ |
WebKit::enableMediaPlayer(); |
} |
+void RenderThread::IdleHandler() { |
+ // It is possible that the timer was set while the widgets were idle, |
+ // but that they are no longer idle. If so, just return. |
+ if (hidden_widget_count_ < widget_count_) |
+ return; |
+ |
+ LOG(INFO) << "RenderThread calling v8 IdleNotification for " << this; |
+ |
+ // When V8::IdleNotification returns true, it means that it has cleaned up |
+ // as much as it can. There is no point in continuing to call it. |
+ if (!v8::V8::IdleNotification(false)) { |
+ // Dampen the delay using the algorithm: |
+ // delay = delay + 1 / (delay + 2) |
+ // Using floor(delay) has a dampening effect such as: |
+ // 1s, 1, 1, 2, 2, 2, 2, 3, 3, ... |
+ idle_notification_delay_in_s_ += |
+ 1.0 / (idle_notification_delay_in_s_ + 2.0); |
+ |
+ // Schedule the next timer. |
+ MessageLoop::current()->PostDelayedTask(FROM_HERE, |
+ task_factory_->NewRunnableMethod(&RenderThread::IdleHandler), |
+ static_cast<int64>(floor(idle_notification_delay_in_s_)) * 1000); |
+ } |
+} |
+ |
void RenderThread::OnExtensionMessageInvoke(const std::string& function_name, |
const ListValue& args) { |
RendererExtensionBindings::Invoke(function_name, args, NULL); |