OLD | NEW |
(Empty) | |
| 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 "content/browser/gpu/gpu_process_host_ui_shim.h" |
| 8 #include "content/browser/renderer_host/render_process_host_impl.h" |
| 9 #include "content/public/browser/browser_thread.h" |
| 10 |
| 11 namespace content { |
| 12 namespace { |
| 13 base::LazyInstance<RenderWidgetResizeHelper> g_render_widget_task_runner = |
| 14 LAZY_INSTANCE_INITIALIZER; |
| 15 } // namespace |
| 16 |
| 17 // A wrapper for IPCs and tasks that we may potentially execute in |
| 18 // WaitForSingleTaskToRun. Because these tasks are sent to two places to run, |
| 19 // we to wrap them in this structure and track whether or not they have run |
| 20 // yet, to avoid running them twice. |
| 21 class RenderWidgetResizeHelper::EnqueuedTask { |
| 22 public: |
| 23 enum Type { |
| 24 RENDERER_IPC, |
| 25 GPU_IPC, |
| 26 }; |
| 27 EnqueuedTask(Type type, int process_id, const IPC::Message& m); |
| 28 ~EnqueuedTask(); |
| 29 void Run(); |
| 30 void InvalidateHelper(); |
| 31 |
| 32 private: |
| 33 Type type_; |
| 34 int process_id_; |
| 35 IPC::Message message_; |
| 36 bool has_run_; |
| 37 RenderWidgetResizeHelper* helper_; |
| 38 |
| 39 DISALLOW_COPY_AND_ASSIGN(EnqueuedTask); |
| 40 }; |
| 41 |
| 42 RenderWidgetResizeHelper::EnqueuedTask::EnqueuedTask( |
| 43 Type type, |
| 44 int process_id, |
| 45 const IPC::Message& m) |
| 46 : type_(type), |
| 47 process_id_(process_id), |
| 48 message_(m), |
| 49 has_run_(false), |
| 50 helper_(RenderWidgetResizeHelper::Get()) { |
| 51 } |
| 52 |
| 53 RenderWidgetResizeHelper::EnqueuedTask::~EnqueuedTask() { |
| 54 } |
| 55 |
| 56 void RenderWidgetResizeHelper::EnqueuedTask::Run() { |
| 57 if (has_run_) |
| 58 return; |
| 59 |
| 60 if (helper_) |
| 61 helper_->WillRunEnqueuedTask(this); |
| 62 has_run_ = true; |
| 63 |
| 64 switch (type_) { |
| 65 case RENDERER_IPC: { |
| 66 RenderProcessHost* host = RenderProcessHost::FromID(process_id_); |
| 67 if (host) |
| 68 host->OnMessageReceived(message_); |
| 69 break; |
| 70 } |
| 71 case GPU_IPC: { |
| 72 GpuProcessHostUIShim* host = GpuProcessHostUIShim::FromID(process_id_); |
| 73 if (host) |
| 74 host->OnMessageReceived(message_); |
| 75 break; |
| 76 } |
| 77 } |
| 78 } |
| 79 |
| 80 void RenderWidgetResizeHelper::EnqueuedTask::InvalidateHelper() { |
| 81 helper_ = NULL; |
| 82 } |
| 83 |
| 84 // static |
| 85 RenderWidgetResizeHelper* RenderWidgetResizeHelper::Get() { |
| 86 return g_render_widget_task_runner.Pointer(); |
| 87 } |
| 88 |
| 89 bool RenderWidgetResizeHelper::WaitForSingleTaskToRun( |
| 90 const base::TimeDelta& max_delay) { |
| 91 base::TimeTicks time_start = base::TimeTicks::Now(); |
| 92 |
| 93 for (;;) { |
| 94 // Peek at the message from the front of the queue. Running it will remove |
| 95 // it from the queue. |
| 96 EnqueuedTask* task = NULL; |
| 97 { |
| 98 base::AutoLock lock(task_queue_lock_); |
| 99 if (!task_queue_.empty()) |
| 100 task = task_queue_.front(); |
| 101 } |
| 102 |
| 103 if (task) { |
| 104 task->Run(); |
| 105 return true; |
| 106 } |
| 107 |
| 108 // Calculate the maximum amount of time that we are willing to sleep. |
| 109 base::TimeDelta max_sleep_time = |
| 110 max_delay - (base::TimeTicks::Now() - time_start); |
| 111 if (max_sleep_time <= base::TimeDelta::FromMilliseconds(0)) |
| 112 break; |
| 113 |
| 114 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
| 115 event_.TimedWait(max_sleep_time); |
| 116 } |
| 117 |
| 118 return false; |
| 119 } |
| 120 |
| 121 void RenderWidgetResizeHelper::PostEnqueuedTask(EnqueuedTask* task) { |
| 122 { |
| 123 base::AutoLock lock(task_queue_lock_); |
| 124 task_queue_.push_back(task); |
| 125 } |
| 126 |
| 127 // Notify anyone waiting on the UI thread that there is a new entry in the |
| 128 // task map. If they don't find the entry they are looking for, then they |
| 129 // will just continue waiting. |
| 130 event_.Signal(); |
| 131 |
| 132 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 133 base::Bind(&EnqueuedTask::Run, base::Owned(task))); |
| 134 } |
| 135 |
| 136 void RenderWidgetResizeHelper::WillRunEnqueuedTask(EnqueuedTask* task) { |
| 137 base::AutoLock lock(task_queue_lock_); |
| 138 DCHECK(task_queue_.front() == task); |
| 139 task_queue_.pop_front(); |
| 140 } |
| 141 |
| 142 void RenderWidgetResizeHelper::PostRendererProcessMsg( |
| 143 int render_process_id, const IPC::Message& msg) { |
| 144 PostEnqueuedTask(new EnqueuedTask( |
| 145 EnqueuedTask::RENDERER_IPC, render_process_id, msg)); |
| 146 } |
| 147 |
| 148 void RenderWidgetResizeHelper::PostGpuProcessMsg( |
| 149 int gpu_host_id, const IPC::Message& msg) { |
| 150 PostEnqueuedTask(new EnqueuedTask(EnqueuedTask::GPU_IPC, gpu_host_id, msg)); |
| 151 } |
| 152 |
| 153 RenderWidgetResizeHelper::RenderWidgetResizeHelper() |
| 154 : event_(false /* auto-reset */, false /* initially signalled */) {} |
| 155 |
| 156 RenderWidgetResizeHelper::~RenderWidgetResizeHelper() { |
| 157 // Ensure that any tasks that outlive this do not reach back into it. |
| 158 for (EnqueuedTaskQueue::iterator it = task_queue_.begin(); |
| 159 it != task_queue_.end(); ++it) { |
| 160 EnqueuedTask* task = *it; |
| 161 task->InvalidateHelper(); |
| 162 } |
| 163 } |
| 164 |
| 165 } // namespace content |
| 166 |
OLD | NEW |