Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / renderer_host / render_widget_resize_helper.cc
blobfe29350db992f8f1bd076fe1347bd5903f43b865
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/render_widget_resize_helper.h"
7 #include <list>
9 #include "content/browser/gpu/gpu_process_host_ui_shim.h"
10 #include "content/browser/renderer_host/render_process_host_impl.h"
11 #include "content/public/browser/browser_thread.h"
13 namespace content {
14 namespace {
16 class WrappedTask;
17 class PumpableTaskRunner;
18 typedef std::list<WrappedTask*> WrappedTaskQueue;
19 typedef base::Callback<void(base::WaitableEvent*, base::TimeDelta)>
20 EventTimedWaitCallback;
22 // A wrapper for IPCs and tasks that we may potentially execute in
23 // WaitForSingleTaskToRun. Because these tasks are sent to two places to run,
24 // we to wrap them in this structure and track whether or not they have run
25 // yet, to avoid running them twice.
26 class WrappedTask {
27 public:
28 WrappedTask(
29 const base::Closure& closure,
30 base::TimeDelta delay);
31 ~WrappedTask();
32 bool ShouldRunBefore(const WrappedTask& other);
33 void Run();
34 void AddToTaskRunnerQueue(PumpableTaskRunner* pumpable_task_runner);
35 void RemoveFromTaskRunnerQueue();
36 const base::TimeTicks& can_run_time() const { return can_run_time_; }
38 private:
39 base::Closure closure_;
40 base::TimeTicks can_run_time_;
41 bool has_run_;
42 uint64 sequence_number_;
43 WrappedTaskQueue::iterator iterator_;
45 // Back pointer to the pumpable task runner that this task is enqueued in.
46 scoped_refptr<PumpableTaskRunner> pumpable_task_runner_;
48 DISALLOW_COPY_AND_ASSIGN(WrappedTask);
51 // The PumpableTaskRunner is a task runner that will wrap tasks in an
52 // WrappedTask, enqueues that wrapped task in the queue to be pumped via
53 // WaitForSingleWrappedTaskToRun during resizes, and posts the task to a
54 // target task runner. The posted task will run only once, either through a
55 // WaitForSingleWrappedTaskToRun call or through the target task runner.
56 class PumpableTaskRunner
57 : public base::SingleThreadTaskRunner {
58 public:
59 explicit PumpableTaskRunner(
60 const EventTimedWaitCallback& event_timed_wait_callback);
62 // Enqueue WrappedTask and post it to |target_task_runner_|.
63 bool EnqueueAndPostWrappedTask(
64 const tracked_objects::Location& from_here,
65 WrappedTask* task,
66 base::TimeDelta delay);
68 // Wait at most |max_delay| to run an enqueued task.
69 bool WaitForSingleWrappedTaskToRun(const base::TimeDelta& max_delay);
71 // Remove a wrapped task from the queue.
72 void RemoveWrappedTaskFromQueue(WrappedTask* task);
74 // base::SingleThreadTaskRunner implementation:
75 virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
76 const base::Closure& task,
77 base::TimeDelta delay) OVERRIDE;
79 virtual bool PostNonNestableDelayedTask(
80 const tracked_objects::Location& from_here,
81 const base::Closure& task,
82 base::TimeDelta delay) OVERRIDE;
84 virtual bool RunsTasksOnCurrentThread() const OVERRIDE;
86 private:
87 friend class WrappedTask;
89 virtual ~PumpableTaskRunner();
91 // A queue of live messages. Must hold |task_queue_lock_| to access. Tasks
92 // are added only on the IO thread and removed only on the UI thread. The
93 // WrappedTask objects are removed from the queue when they are run (by
94 // |target_task_runner_| or by a call to WaitForSingleWrappedTaskToRun
95 // removing them out of the queue, or by TaskRunner when it is destroyed).
96 WrappedTaskQueue task_queue_;
97 base::Lock task_queue_lock_;
99 // Event used to wake up the UI thread if it is sleeping in
100 // WaitForSingleTaskToRun.
101 base::WaitableEvent event_;
103 // Callback to call TimedWait on |event_| from an appropriate class.
104 EventTimedWaitCallback event_timed_wait_callback_;
106 scoped_refptr<base::SingleThreadTaskRunner> target_task_runner_;
108 DISALLOW_COPY_AND_ASSIGN(PumpableTaskRunner);
111 void HandleGpuIPC(int gpu_host_id, const IPC::Message& message) {
112 GpuProcessHostUIShim* host = GpuProcessHostUIShim::FromID(gpu_host_id);
113 if (host)
114 host->OnMessageReceived(message);
117 void HandleRendererIPC(int render_process_id, const IPC::Message& message) {
118 RenderProcessHost* host = RenderProcessHost::FromID(render_process_id);
119 if (host)
120 host->OnMessageReceived(message);
123 base::LazyInstance<RenderWidgetResizeHelper> g_render_widget_task_runner =
124 LAZY_INSTANCE_INITIALIZER;
126 ////////////////////////////////////////////////////////////////////////////////
127 // WrappedTask
129 WrappedTask::WrappedTask(
130 const base::Closure& closure,
131 base::TimeDelta delay)
132 : closure_(closure),
133 can_run_time_(base::TimeTicks::Now() + delay),
134 has_run_(false),
135 sequence_number_(0) {
138 WrappedTask::~WrappedTask() {
139 RemoveFromTaskRunnerQueue();
142 bool WrappedTask::ShouldRunBefore(const WrappedTask& other) {
143 if (can_run_time_ < other.can_run_time_)
144 return true;
145 if (can_run_time_ > other.can_run_time_)
146 return false;
147 if (sequence_number_ < other.sequence_number_)
148 return true;
149 if (sequence_number_ > other.sequence_number_)
150 return false;
151 // Sequence numbers are unique, so this should never happen.
152 NOTREACHED();
153 return false;
156 void WrappedTask::Run() {
157 if (has_run_)
158 return;
159 RemoveFromTaskRunnerQueue();
160 has_run_ = true;
161 closure_.Run();
164 void WrappedTask::AddToTaskRunnerQueue(
165 PumpableTaskRunner* pumpable_task_runner) {
166 pumpable_task_runner_ = pumpable_task_runner;
167 base::AutoLock lock(pumpable_task_runner_->task_queue_lock_);
168 static uint64 last_sequence_number = 0;
169 last_sequence_number += 1;
170 sequence_number_ = last_sequence_number;
171 iterator_ = pumpable_task_runner_->task_queue_.insert(
172 pumpable_task_runner_->task_queue_.end(), this);
175 void WrappedTask::RemoveFromTaskRunnerQueue() {
176 if (!pumpable_task_runner_.get())
177 return;
178 // The scope of the task runner's lock must be limited because removing
179 // this reference to the task runner may destroy it.
181 base::AutoLock lock(pumpable_task_runner_->task_queue_lock_);
182 pumpable_task_runner_->task_queue_.erase(iterator_);
183 iterator_ = pumpable_task_runner_->task_queue_.end();
185 pumpable_task_runner_ = NULL;
188 ////////////////////////////////////////////////////////////////////////////////
189 // PumpableTaskRunner
191 PumpableTaskRunner::PumpableTaskRunner(
192 const EventTimedWaitCallback& event_timed_wait_callback)
193 : event_(false /* auto-reset */, false /* initially signalled */),
194 event_timed_wait_callback_(event_timed_wait_callback),
195 target_task_runner_(BrowserThread::GetMessageLoopProxyForThread(
196 BrowserThread::UI)) {}
198 PumpableTaskRunner::~PumpableTaskRunner() {
199 // Because tasks hold a reference to the task runner, the task queue must
200 // be empty when it is destroyed.
201 DCHECK(task_queue_.empty());
204 bool PumpableTaskRunner::WaitForSingleWrappedTaskToRun(
205 const base::TimeDelta& max_delay) {
206 base::TimeTicks stop_waiting_time = base::TimeTicks::Now() + max_delay;
208 for (;;) {
209 base::TimeTicks current_time = base::TimeTicks::Now();
210 base::TimeTicks next_task_time = stop_waiting_time;
212 // Find the first task to execute in the list. This lookup takes O(n) time,
213 // but n is rarely more than 2, and has never been observed to be more than
214 // 12.
215 WrappedTask* task_to_execute = NULL;
217 base::AutoLock lock(task_queue_lock_);
219 for (WrappedTaskQueue::iterator it = task_queue_.begin(); it !=
220 task_queue_.end(); ++it) {
221 WrappedTask* potential_task = *it;
223 // If this task is scheduled for the future, take it into account when
224 // deciding how long to sleep, and continue on to the next task.
225 if (potential_task->can_run_time() > current_time) {
226 if (potential_task->can_run_time() < next_task_time)
227 next_task_time = potential_task->can_run_time();
228 continue;
230 // If there is a better candidate than this task, continue to the next
231 // task.
232 if (task_to_execute &&
233 task_to_execute->ShouldRunBefore(*potential_task)) {
234 continue;
236 task_to_execute = potential_task;
240 if (task_to_execute) {
241 task_to_execute->Run();
242 return true;
245 // Calculate how much time we have left before we have to stop waiting or
246 // until a currently-enqueued task will be ready to run.
247 base::TimeDelta max_sleep_time = next_task_time - current_time;
248 if (max_sleep_time <= base::TimeDelta::FromMilliseconds(0))
249 break;
251 event_timed_wait_callback_.Run(&event_, max_sleep_time);
254 return false;
257 bool PumpableTaskRunner::EnqueueAndPostWrappedTask(
258 const tracked_objects::Location& from_here,
259 WrappedTask* task,
260 base::TimeDelta delay) {
261 task->AddToTaskRunnerQueue(this);
263 // Notify anyone waiting on the UI thread that there is a new entry in the
264 // task map. If they don't find the entry they are looking for, then they
265 // will just continue waiting.
266 event_.Signal();
268 return target_task_runner_->PostDelayedTask(
269 from_here, base::Bind(&WrappedTask::Run, base::Owned(task)), delay);
272 ////////////////////////////////////////////////////////////////////////////////
273 // PumpableTaskRunner, base::SingleThreadTaskRunner implementation:
275 bool PumpableTaskRunner::PostDelayedTask(
276 const tracked_objects::Location& from_here,
277 const base::Closure& task,
278 base::TimeDelta delay) {
279 return EnqueueAndPostWrappedTask(
280 from_here,
281 new WrappedTask(task, delay),
282 delay);
285 bool PumpableTaskRunner::PostNonNestableDelayedTask(
286 const tracked_objects::Location& from_here,
287 const base::Closure& task,
288 base::TimeDelta delay) {
289 // The correctness of non-nestable events hasn't been proven for this
290 // structure.
291 NOTREACHED();
292 return false;
295 bool PumpableTaskRunner::RunsTasksOnCurrentThread() const {
296 return target_task_runner_->RunsTasksOnCurrentThread();
299 } // namespace
301 ////////////////////////////////////////////////////////////////////////////////
302 // RenderWidgetResizeHelper
304 scoped_refptr<base::SingleThreadTaskRunner>
305 RenderWidgetResizeHelper::task_runner() const {
306 return task_runner_;
309 // static
310 RenderWidgetResizeHelper* RenderWidgetResizeHelper::Get() {
311 return g_render_widget_task_runner.Pointer();
314 bool RenderWidgetResizeHelper::WaitForSingleTaskToRun(
315 const base::TimeDelta& max_delay) {
316 PumpableTaskRunner* pumpable_task_runner =
317 reinterpret_cast<PumpableTaskRunner*>(task_runner_.get());
318 return pumpable_task_runner->WaitForSingleWrappedTaskToRun(max_delay);
321 void RenderWidgetResizeHelper::PostRendererProcessMsg(
322 int render_process_id, const IPC::Message& msg) {
323 PumpableTaskRunner* pumpable_task_runner =
324 reinterpret_cast<PumpableTaskRunner*>(task_runner_.get());
325 pumpable_task_runner->EnqueueAndPostWrappedTask(
326 FROM_HERE,
327 new WrappedTask(base::Bind(HandleRendererIPC, render_process_id, msg),
328 base::TimeDelta()),
329 base::TimeDelta());
332 void RenderWidgetResizeHelper::PostGpuProcessMsg(
333 int gpu_host_id, const IPC::Message& msg) {
334 PumpableTaskRunner* pumpable_task_runner =
335 reinterpret_cast<PumpableTaskRunner*>(task_runner_.get());
336 pumpable_task_runner->EnqueueAndPostWrappedTask(
337 FROM_HERE,
338 new WrappedTask(base::Bind(HandleGpuIPC, gpu_host_id, msg),
339 base::TimeDelta()),
340 base::TimeDelta());
343 RenderWidgetResizeHelper::RenderWidgetResizeHelper() {
344 task_runner_ = new PumpableTaskRunner(base::Bind(&EventTimedWait));
347 RenderWidgetResizeHelper::~RenderWidgetResizeHelper() {}
349 // static
350 void RenderWidgetResizeHelper::EventTimedWait(
351 base::WaitableEvent* event, base::TimeDelta delay) {
352 base::ThreadRestrictions::ScopedAllowWait allow_wait;
353 event->TimedWait(delay);
356 } // namespace content