Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / render_widget_resize_helper.cc
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.
4
5 #include "content/browser/renderer_host/render_widget_resize_helper.h"
6
7 #include <list>
8
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"
12
13 namespace content {
14 namespace {
15
16 class WrappedTask;
17 class PumpableTaskRunner;
18 typedef std::list<WrappedTask*> WrappedTaskQueue;
19 typedef base::Callback<void(base::WaitableEvent*, base::TimeDelta)>
20     EventTimedWaitCallback;
21
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_; }
37
38  private:
39   base::Closure closure_;
40   base::TimeTicks can_run_time_;
41   bool has_run_;
42   uint64 sequence_number_;
43   WrappedTaskQueue::iterator iterator_;
44
45   // Back pointer to the pumpable task runner that this task is enqueued in.
46   scoped_refptr<PumpableTaskRunner> pumpable_task_runner_;
47
48   DISALLOW_COPY_AND_ASSIGN(WrappedTask);
49 };
50
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);
61
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);
67
68   // Wait at most |max_delay| to run an enqueued task.
69   bool WaitForSingleWrappedTaskToRun(const base::TimeDelta& max_delay);
70
71   // Remove a wrapped task from the queue.
72   void RemoveWrappedTaskFromQueue(WrappedTask* task);
73
74   // base::SingleThreadTaskRunner implementation:
75   virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
76                                const base::Closure& task,
77                                base::TimeDelta delay) OVERRIDE;
78
79   virtual bool PostNonNestableDelayedTask(
80       const tracked_objects::Location& from_here,
81       const base::Closure& task,
82       base::TimeDelta delay) OVERRIDE;
83
84   virtual bool RunsTasksOnCurrentThread() const OVERRIDE;
85
86  private:
87   friend class WrappedTask;
88
89   virtual ~PumpableTaskRunner();
90
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_;
98
99   // Event used to wake up the UI thread if it is sleeping in
100   // WaitForSingleTaskToRun.
101   base::WaitableEvent event_;
102
103   // Callback to call TimedWait on |event_| from an appropriate class.
104   EventTimedWaitCallback event_timed_wait_callback_;
105
106   scoped_refptr<base::SingleThreadTaskRunner> target_task_runner_;
107
108   DISALLOW_COPY_AND_ASSIGN(PumpableTaskRunner);
109 };
110
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);
115 }
116
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);
121 }
122
123 base::LazyInstance<RenderWidgetResizeHelper> g_render_widget_task_runner =
124     LAZY_INSTANCE_INITIALIZER;
125
126 ////////////////////////////////////////////////////////////////////////////////
127 // WrappedTask
128
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) {
136 }
137
138 WrappedTask::~WrappedTask() {
139   RemoveFromTaskRunnerQueue();
140 }
141
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;
154 }
155
156 void WrappedTask::Run() {
157   if (has_run_)
158     return;
159   RemoveFromTaskRunnerQueue();
160   has_run_ = true;
161   closure_.Run();
162 }
163
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);
173 }
174
175 void WrappedTask::RemoveFromTaskRunnerQueue() {
176   if (!pumpable_task_runner_)
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.
180   {
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();
184   }
185   pumpable_task_runner_ = NULL;
186 }
187
188 ////////////////////////////////////////////////////////////////////////////////
189 // PumpableTaskRunner
190
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)) {}
197
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());
202 }
203
204 bool PumpableTaskRunner::WaitForSingleWrappedTaskToRun(
205     const base::TimeDelta& max_delay) {
206   base::TimeTicks stop_waiting_time = base::TimeTicks::Now() + max_delay;
207
208   for (;;) {
209     base::TimeTicks current_time = base::TimeTicks::Now();
210     base::TimeTicks next_task_time = stop_waiting_time;
211
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;
216     {
217       base::AutoLock lock(task_queue_lock_);
218
219       for (WrappedTaskQueue::iterator it = task_queue_.begin(); it !=
220                task_queue_.end(); ++it) {
221         WrappedTask* potential_task = *it;
222
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;
229         }
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;
235         }
236         task_to_execute = potential_task;
237       }
238     }
239
240     if (task_to_execute) {
241       task_to_execute->Run();
242       return true;
243     }
244
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;
250
251     event_timed_wait_callback_.Run(&event_, max_sleep_time);
252   }
253
254   return false;
255 }
256
257 bool PumpableTaskRunner::EnqueueAndPostWrappedTask(
258     const tracked_objects::Location& from_here,
259     WrappedTask* task,
260     base::TimeDelta delay) {
261   task->AddToTaskRunnerQueue(this);
262
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();
267
268   return target_task_runner_->PostDelayedTask(
269         from_here, base::Bind(&WrappedTask::Run, base::Owned(task)), delay);
270 }
271
272 ////////////////////////////////////////////////////////////////////////////////
273 // PumpableTaskRunner, base::SingleThreadTaskRunner implementation:
274
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);
283 }
284
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;
293 }
294
295 bool PumpableTaskRunner::RunsTasksOnCurrentThread() const {
296   return target_task_runner_->RunsTasksOnCurrentThread();
297 }
298
299 }  // namespace
300
301 ////////////////////////////////////////////////////////////////////////////////
302 // RenderWidgetResizeHelper
303
304 scoped_refptr<base::SingleThreadTaskRunner>
305     RenderWidgetResizeHelper::task_runner() const {
306   return task_runner_;
307 }
308
309 // static
310 RenderWidgetResizeHelper* RenderWidgetResizeHelper::Get() {
311   return g_render_widget_task_runner.Pointer();
312 }
313
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);
319 }
320
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());
330 }
331
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());
341 }
342
343 RenderWidgetResizeHelper::RenderWidgetResizeHelper() {
344   task_runner_ = new PumpableTaskRunner(base::Bind(&EventTimedWait));
345 }
346
347 RenderWidgetResizeHelper::~RenderWidgetResizeHelper() {}
348
349 // static
350 void RenderWidgetResizeHelper::EventTimedWait(
351     base::WaitableEvent* event, base::TimeDelta delay) {
352   base::ThreadRestrictions::ScopedAllowWait allow_wait;
353   event->TimedWait(delay);
354 }
355
356 }  // namespace content
357