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_.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. 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 358