Roll src/third_party/WebKit eac3800:0237a66 (svn 202606:202607)
[chromium-blink-merge.git] / content / browser / renderer_host / render_widget_resize_helper_mac.cc
blob823c6848602586e12be00b7b75c18ccdbda1aa58
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_mac.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(const base::Closure& closure, base::TimeDelta delay);
29 ~WrappedTask();
30 bool ShouldRunBefore(const WrappedTask& other);
31 void Run();
32 void AddToTaskRunnerQueue(PumpableTaskRunner* pumpable_task_runner);
33 void RemoveFromTaskRunnerQueue();
34 const base::TimeTicks& can_run_time() const { return can_run_time_; }
36 private:
37 base::Closure closure_;
38 base::TimeTicks can_run_time_;
39 bool has_run_;
40 uint64 sequence_number_;
41 WrappedTaskQueue::iterator iterator_;
43 // Back pointer to the pumpable task runner that this task is enqueued in.
44 scoped_refptr<PumpableTaskRunner> pumpable_task_runner_;
46 DISALLOW_COPY_AND_ASSIGN(WrappedTask);
49 // The PumpableTaskRunner is a task runner that will wrap tasks in an
50 // WrappedTask, enqueues that wrapped task in the queue to be pumped via
51 // WaitForSingleWrappedTaskToRun during resizes, and posts the task to a
52 // target task runner. The posted task will run only once, either through a
53 // WaitForSingleWrappedTaskToRun call or through the target task runner.
54 class PumpableTaskRunner : public base::SingleThreadTaskRunner {
55 public:
56 explicit PumpableTaskRunner(
57 const EventTimedWaitCallback& event_timed_wait_callback);
59 // Enqueue WrappedTask and post it to |target_task_runner_|.
60 bool EnqueueAndPostWrappedTask(const tracked_objects::Location& from_here,
61 WrappedTask* task,
62 base::TimeDelta delay);
64 // Wait at most |max_delay| to run an enqueued task.
65 bool WaitForSingleWrappedTaskToRun(const base::TimeDelta& max_delay);
67 // Remove a wrapped task from the queue.
68 void RemoveWrappedTaskFromQueue(WrappedTask* task);
70 // base::SingleThreadTaskRunner implementation:
71 bool PostDelayedTask(const tracked_objects::Location& from_here,
72 const base::Closure& task,
73 base::TimeDelta delay) override;
75 bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
76 const base::Closure& task,
77 base::TimeDelta delay) override;
79 bool RunsTasksOnCurrentThread() const override;
81 private:
82 friend class WrappedTask;
84 ~PumpableTaskRunner() override;
86 // A queue of live messages. Must hold |task_queue_lock_| to access. Tasks
87 // are added only on the IO thread and removed only on the UI thread. The
88 // WrappedTask objects are removed from the queue when they are run (by
89 // |target_task_runner_| or by a call to WaitForSingleWrappedTaskToRun
90 // removing them out of the queue, or by TaskRunner when it is destroyed).
91 WrappedTaskQueue task_queue_;
92 base::Lock task_queue_lock_;
94 // Event used to wake up the UI thread if it is sleeping in
95 // WaitForSingleTaskToRun.
96 base::WaitableEvent event_;
98 // Callback to call TimedWait on |event_| from an appropriate class.
99 EventTimedWaitCallback event_timed_wait_callback_;
101 scoped_refptr<base::SingleThreadTaskRunner> target_task_runner_;
103 DISALLOW_COPY_AND_ASSIGN(PumpableTaskRunner);
106 void HandleGpuIPC(int gpu_host_id, const IPC::Message& message) {
107 GpuProcessHostUIShim* host = GpuProcessHostUIShim::FromID(gpu_host_id);
108 if (host)
109 host->OnMessageReceived(message);
112 void HandleRendererIPC(int render_process_id, const IPC::Message& message) {
113 RenderProcessHost* host = RenderProcessHost::FromID(render_process_id);
114 if (host)
115 host->OnMessageReceived(message);
118 base::LazyInstance<RenderWidgetResizeHelper> g_render_widget_task_runner =
119 LAZY_INSTANCE_INITIALIZER;
121 ////////////////////////////////////////////////////////////////////////////////
122 // WrappedTask
124 WrappedTask::WrappedTask(const base::Closure& closure, base::TimeDelta delay)
125 : closure_(closure),
126 can_run_time_(base::TimeTicks::Now() + delay),
127 has_run_(false),
128 sequence_number_(0) {}
130 WrappedTask::~WrappedTask() {
131 RemoveFromTaskRunnerQueue();
134 bool WrappedTask::ShouldRunBefore(const WrappedTask& other) {
135 if (can_run_time_ < other.can_run_time_)
136 return true;
137 if (can_run_time_ > other.can_run_time_)
138 return false;
139 if (sequence_number_ < other.sequence_number_)
140 return true;
141 if (sequence_number_ > other.sequence_number_)
142 return false;
143 // Sequence numbers are unique, so this should never happen.
144 NOTREACHED();
145 return false;
148 void WrappedTask::Run() {
149 if (has_run_)
150 return;
151 RemoveFromTaskRunnerQueue();
152 has_run_ = true;
153 closure_.Run();
156 void WrappedTask::AddToTaskRunnerQueue(
157 PumpableTaskRunner* pumpable_task_runner) {
158 pumpable_task_runner_ = pumpable_task_runner;
159 base::AutoLock lock(pumpable_task_runner_->task_queue_lock_);
160 static uint64 last_sequence_number = 0;
161 last_sequence_number += 1;
162 sequence_number_ = last_sequence_number;
163 iterator_ = pumpable_task_runner_->task_queue_.insert(
164 pumpable_task_runner_->task_queue_.end(), this);
167 void WrappedTask::RemoveFromTaskRunnerQueue() {
168 if (!pumpable_task_runner_.get())
169 return;
170 // The scope of the task runner's lock must be limited because removing
171 // this reference to the task runner may destroy it.
173 base::AutoLock lock(pumpable_task_runner_->task_queue_lock_);
174 pumpable_task_runner_->task_queue_.erase(iterator_);
175 iterator_ = pumpable_task_runner_->task_queue_.end();
177 pumpable_task_runner_ = NULL;
180 ////////////////////////////////////////////////////////////////////////////////
181 // PumpableTaskRunner
183 PumpableTaskRunner::PumpableTaskRunner(
184 const EventTimedWaitCallback& event_timed_wait_callback)
185 : event_(false /* auto-reset */, false /* initially signalled */),
186 event_timed_wait_callback_(event_timed_wait_callback),
187 target_task_runner_(
188 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI)) {}
190 PumpableTaskRunner::~PumpableTaskRunner() {
191 // Because tasks hold a reference to the task runner, the task queue must
192 // be empty when it is destroyed.
193 DCHECK(task_queue_.empty());
196 bool PumpableTaskRunner::WaitForSingleWrappedTaskToRun(
197 const base::TimeDelta& max_delay) {
198 base::TimeTicks stop_waiting_time = base::TimeTicks::Now() + max_delay;
200 for (;;) {
201 base::TimeTicks current_time = base::TimeTicks::Now();
202 base::TimeTicks next_task_time = stop_waiting_time;
204 // Find the first task to execute in the list. This lookup takes O(n) time,
205 // but n is rarely more than 2, and has never been observed to be more than
206 // 12.
207 WrappedTask* task_to_execute = NULL;
209 base::AutoLock lock(task_queue_lock_);
211 for (WrappedTaskQueue::iterator it = task_queue_.begin();
212 it != task_queue_.end(); ++it) {
213 WrappedTask* potential_task = *it;
215 // If this task is scheduled for the future, take it into account when
216 // deciding how long to sleep, and continue on to the next task.
217 if (potential_task->can_run_time() > current_time) {
218 if (potential_task->can_run_time() < next_task_time)
219 next_task_time = potential_task->can_run_time();
220 continue;
222 // If there is a better candidate than this task, continue to the next
223 // task.
224 if (task_to_execute &&
225 task_to_execute->ShouldRunBefore(*potential_task)) {
226 continue;
228 task_to_execute = potential_task;
232 if (task_to_execute) {
233 task_to_execute->Run();
234 return true;
237 // Calculate how much time we have left before we have to stop waiting or
238 // until a currently-enqueued task will be ready to run.
239 base::TimeDelta max_sleep_time = next_task_time - current_time;
240 if (max_sleep_time <= base::TimeDelta::FromMilliseconds(0))
241 break;
243 event_timed_wait_callback_.Run(&event_, max_sleep_time);
246 return false;
249 bool PumpableTaskRunner::EnqueueAndPostWrappedTask(
250 const tracked_objects::Location& from_here,
251 WrappedTask* task,
252 base::TimeDelta delay) {
253 task->AddToTaskRunnerQueue(this);
255 // Notify anyone waiting on the UI thread that there is a new entry in the
256 // task map. If they don't find the entry they are looking for, then they
257 // will just continue waiting.
258 event_.Signal();
260 return target_task_runner_->PostDelayedTask(
261 from_here, base::Bind(&WrappedTask::Run, base::Owned(task)), delay);
264 ////////////////////////////////////////////////////////////////////////////////
265 // PumpableTaskRunner, base::SingleThreadTaskRunner implementation:
267 bool PumpableTaskRunner::PostDelayedTask(
268 const tracked_objects::Location& from_here,
269 const base::Closure& task,
270 base::TimeDelta delay) {
271 return EnqueueAndPostWrappedTask(from_here, new WrappedTask(task, delay),
272 delay);
275 bool PumpableTaskRunner::PostNonNestableDelayedTask(
276 const tracked_objects::Location& from_here,
277 const base::Closure& task,
278 base::TimeDelta delay) {
279 // The correctness of non-nestable events hasn't been proven for this
280 // structure.
281 NOTREACHED();
282 return false;
285 bool PumpableTaskRunner::RunsTasksOnCurrentThread() const {
286 return target_task_runner_->RunsTasksOnCurrentThread();
289 } // namespace
291 ////////////////////////////////////////////////////////////////////////////////
292 // RenderWidgetResizeHelper
294 scoped_refptr<base::SingleThreadTaskRunner>
295 RenderWidgetResizeHelper::task_runner() const {
296 return task_runner_;
299 // static
300 RenderWidgetResizeHelper* RenderWidgetResizeHelper::Get() {
301 return g_render_widget_task_runner.Pointer();
304 bool RenderWidgetResizeHelper::WaitForSingleTaskToRun(
305 const base::TimeDelta& max_delay) {
306 PumpableTaskRunner* pumpable_task_runner =
307 reinterpret_cast<PumpableTaskRunner*>(task_runner_.get());
308 return pumpable_task_runner->WaitForSingleWrappedTaskToRun(max_delay);
311 void RenderWidgetResizeHelper::PostRendererProcessMsg(int render_process_id,
312 const IPC::Message& msg) {
313 PumpableTaskRunner* pumpable_task_runner =
314 reinterpret_cast<PumpableTaskRunner*>(task_runner_.get());
315 pumpable_task_runner->EnqueueAndPostWrappedTask(
316 FROM_HERE,
317 new WrappedTask(base::Bind(HandleRendererIPC, render_process_id, msg),
318 base::TimeDelta()),
319 base::TimeDelta());
322 void RenderWidgetResizeHelper::PostGpuProcessMsg(int gpu_host_id,
323 const IPC::Message& msg) {
324 PumpableTaskRunner* pumpable_task_runner =
325 reinterpret_cast<PumpableTaskRunner*>(task_runner_.get());
326 pumpable_task_runner->EnqueueAndPostWrappedTask(
327 FROM_HERE, new WrappedTask(base::Bind(HandleGpuIPC, gpu_host_id, msg),
328 base::TimeDelta()),
329 base::TimeDelta());
332 RenderWidgetResizeHelper::RenderWidgetResizeHelper() {
333 task_runner_ = new PumpableTaskRunner(base::Bind(&EventTimedWait));
336 RenderWidgetResizeHelper::~RenderWidgetResizeHelper() {}
338 // static
339 void RenderWidgetResizeHelper::EventTimedWait(base::WaitableEvent* event,
340 base::TimeDelta delay) {
341 base::ThreadRestrictions::ScopedAllowWait allow_wait;
342 event->TimedWait(delay);
345 } // namespace content