| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/renderer_host/render_widget_helper.h" | 5 #include "content/browser/renderer_host/render_widget_helper.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
| 10 #include "base/posix/eintr_wrapper.h" | 10 #include "base/posix/eintr_wrapper.h" |
| 11 #include "base/threading/thread.h" | 11 #include "base/threading/thread.h" |
| 12 #include "base/threading/thread_restrictions.h" | 12 #include "base/threading/thread_restrictions.h" |
| 13 #include "content/browser/gpu/gpu_process_host_ui_shim.h" |
| 13 #include "content/browser/gpu/gpu_surface_tracker.h" | 14 #include "content/browser/gpu/gpu_surface_tracker.h" |
| 14 #include "content/browser/loader/resource_dispatcher_host_impl.h" | 15 #include "content/browser/loader/resource_dispatcher_host_impl.h" |
| 15 #include "content/browser/renderer_host/render_process_host_impl.h" | 16 #include "content/browser/renderer_host/render_process_host_impl.h" |
| 16 #include "content/browser/renderer_host/render_view_host_impl.h" | 17 #include "content/browser/renderer_host/render_view_host_impl.h" |
| 17 #include "content/browser/dom_storage/session_storage_namespace_impl.h" | 18 #include "content/browser/dom_storage/session_storage_namespace_impl.h" |
| 18 #include "content/common/view_messages.h" | 19 #include "content/common/view_messages.h" |
| 19 | 20 |
| 20 namespace content { | 21 namespace content { |
| 21 namespace { | 22 namespace { |
| 22 | 23 |
| 23 typedef std::map<int, RenderWidgetHelper*> WidgetHelperMap; | 24 typedef std::map<int, RenderWidgetHelper*> WidgetHelperMap; |
| 24 base::LazyInstance<WidgetHelperMap> g_widget_helpers = | 25 base::LazyInstance<WidgetHelperMap> g_widget_helpers = |
| 25 LAZY_INSTANCE_INITIALIZER; | 26 LAZY_INSTANCE_INITIALIZER; |
| 26 | 27 |
| 27 void AddWidgetHelper(int render_process_id, | 28 void AddWidgetHelper(int render_process_id, |
| 28 const scoped_refptr<RenderWidgetHelper>& widget_helper) { | 29 const scoped_refptr<RenderWidgetHelper>& widget_helper) { |
| 29 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 30 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 30 // We don't care if RenderWidgetHelpers overwrite an existing process_id. Just | 31 // We don't care if RenderWidgetHelpers overwrite an existing process_id. Just |
| 31 // want this to be up to date. | 32 // want this to be up to date. |
| 32 g_widget_helpers.Get()[render_process_id] = widget_helper.get(); | 33 g_widget_helpers.Get()[render_process_id] = widget_helper.get(); |
| 33 } | 34 } |
| 34 | 35 |
| 35 } // namespace | 36 } // namespace |
| 36 | 37 |
| 37 // A helper used with DidReceiveBackingStoreMsg that we hold a pointer to in | |
| 38 // pending_paints_. | |
| 39 class RenderWidgetHelper::BackingStoreMsgProxy { | |
| 40 public: | |
| 41 BackingStoreMsgProxy(RenderWidgetHelper* h, const IPC::Message& m); | |
| 42 ~BackingStoreMsgProxy(); | |
| 43 void Run(); | |
| 44 void Cancel() { cancelled_ = true; } | |
| 45 | |
| 46 const IPC::Message& message() const { return message_; } | |
| 47 | |
| 48 private: | |
| 49 scoped_refptr<RenderWidgetHelper> helper_; | |
| 50 IPC::Message message_; | |
| 51 bool cancelled_; // If true, then the message will not be dispatched. | |
| 52 | |
| 53 DISALLOW_COPY_AND_ASSIGN(BackingStoreMsgProxy); | |
| 54 }; | |
| 55 | |
| 56 RenderWidgetHelper::BackingStoreMsgProxy::BackingStoreMsgProxy( | |
| 57 RenderWidgetHelper* h, const IPC::Message& m) | |
| 58 : helper_(h), | |
| 59 message_(m), | |
| 60 cancelled_(false) { | |
| 61 } | |
| 62 | |
| 63 RenderWidgetHelper::BackingStoreMsgProxy::~BackingStoreMsgProxy() { | |
| 64 // If the paint message was never dispatched, then we need to let the | |
| 65 // helper know that we are going away. | |
| 66 if (!cancelled_ && helper_.get()) | |
| 67 helper_->OnDiscardBackingStoreMsg(this); | |
| 68 } | |
| 69 | |
| 70 void RenderWidgetHelper::BackingStoreMsgProxy::Run() { | |
| 71 if (!cancelled_) { | |
| 72 helper_->OnDispatchBackingStoreMsg(this); | |
| 73 helper_ = NULL; | |
| 74 } | |
| 75 } | |
| 76 | |
| 77 RenderWidgetHelper::RenderWidgetHelper() | 38 RenderWidgetHelper::RenderWidgetHelper() |
| 78 : render_process_id_(-1), | 39 : render_process_id_(-1), |
| 79 #if defined(OS_WIN) | |
| 80 event_(CreateEvent(NULL, FALSE /* auto-reset */, FALSE, NULL)), | |
| 81 #elif defined(OS_POSIX) | |
| 82 event_(false /* auto-reset */, false), | |
| 83 #endif | |
| 84 resource_dispatcher_host_(NULL) { | 40 resource_dispatcher_host_(NULL) { |
| 85 } | 41 } |
| 86 | 42 |
| 87 RenderWidgetHelper::~RenderWidgetHelper() { | 43 RenderWidgetHelper::~RenderWidgetHelper() { |
| 88 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 44 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 89 | 45 |
| 90 // Delete this RWH from the map if it is found. | 46 // Delete this RWH from the map if it is found. |
| 91 WidgetHelperMap& widget_map = g_widget_helpers.Get(); | 47 WidgetHelperMap& widget_map = g_widget_helpers.Get(); |
| 92 WidgetHelperMap::iterator it = widget_map.find(render_process_id_); | 48 WidgetHelperMap::iterator it = widget_map.find(render_process_id_); |
| 93 if (it != widget_map.end() && it->second == this) | 49 if (it != widget_map.end() && it->second == this) |
| 94 widget_map.erase(it); | 50 widget_map.erase(it); |
| 95 | 51 |
| 96 // The elements of pending_paints_ each hold an owning reference back to this | |
| 97 // object, so we should not be destroyed unless pending_paints_ is empty! | |
| 98 DCHECK(pending_paints_.empty()); | |
| 99 | |
| 100 #if defined(OS_POSIX) && !defined(OS_ANDROID) | 52 #if defined(OS_POSIX) && !defined(OS_ANDROID) |
| 101 ClearAllocatedDIBs(); | 53 ClearAllocatedDIBs(); |
| 102 #endif | 54 #endif |
| 103 } | 55 } |
| 104 | 56 |
| 105 void RenderWidgetHelper::Init( | 57 void RenderWidgetHelper::Init( |
| 106 int render_process_id, | 58 int render_process_id, |
| 107 ResourceDispatcherHostImpl* resource_dispatcher_host) { | 59 ResourceDispatcherHostImpl* resource_dispatcher_host) { |
| 108 render_process_id_ = render_process_id; | 60 render_process_id_ = render_process_id; |
| 109 resource_dispatcher_host_ = resource_dispatcher_host; | 61 resource_dispatcher_host_ = resource_dispatcher_host; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 139 void RenderWidgetHelper::ResumeResponseDeferredAtStart( | 91 void RenderWidgetHelper::ResumeResponseDeferredAtStart( |
| 140 const GlobalRequestID& request_id) { | 92 const GlobalRequestID& request_id) { |
| 141 BrowserThread::PostTask( | 93 BrowserThread::PostTask( |
| 142 BrowserThread::IO, | 94 BrowserThread::IO, |
| 143 FROM_HERE, | 95 FROM_HERE, |
| 144 base::Bind(&RenderWidgetHelper::OnResumeResponseDeferredAtStart, | 96 base::Bind(&RenderWidgetHelper::OnResumeResponseDeferredAtStart, |
| 145 this, | 97 this, |
| 146 request_id)); | 98 request_id)); |
| 147 } | 99 } |
| 148 | 100 |
| 149 bool RenderWidgetHelper::WaitForBackingStoreMsg( | |
| 150 int render_widget_id, const base::TimeDelta& max_delay, IPC::Message* msg) { | |
| 151 base::TimeTicks time_start = base::TimeTicks::Now(); | |
| 152 | |
| 153 for (;;) { | |
| 154 BackingStoreMsgProxy* proxy = NULL; | |
| 155 { | |
| 156 base::AutoLock lock(pending_paints_lock_); | |
| 157 | |
| 158 BackingStoreMsgProxyMap::iterator it = | |
| 159 pending_paints_.find(render_widget_id); | |
| 160 if (it != pending_paints_.end()) { | |
| 161 BackingStoreMsgProxyQueue &queue = it->second; | |
| 162 DCHECK(!queue.empty()); | |
| 163 proxy = queue.front(); | |
| 164 | |
| 165 // Flag the proxy as cancelled so that when it is run as a task it will | |
| 166 // do nothing. | |
| 167 proxy->Cancel(); | |
| 168 | |
| 169 queue.pop_front(); | |
| 170 if (queue.empty()) | |
| 171 pending_paints_.erase(it); | |
| 172 } | |
| 173 } | |
| 174 | |
| 175 if (proxy) { | |
| 176 *msg = proxy->message(); | |
| 177 DCHECK(msg->routing_id() == render_widget_id); | |
| 178 return true; | |
| 179 } | |
| 180 | |
| 181 // Calculate the maximum amount of time that we are willing to sleep. | |
| 182 base::TimeDelta max_sleep_time = | |
| 183 max_delay - (base::TimeTicks::Now() - time_start); | |
| 184 if (max_sleep_time <= base::TimeDelta::FromMilliseconds(0)) | |
| 185 break; | |
| 186 | |
| 187 base::ThreadRestrictions::ScopedAllowWait allow_wait; | |
| 188 event_.TimedWait(max_sleep_time); | |
| 189 } | |
| 190 | |
| 191 return false; | |
| 192 } | |
| 193 | |
| 194 void RenderWidgetHelper::ResumeRequestsForView(int route_id) { | 101 void RenderWidgetHelper::ResumeRequestsForView(int route_id) { |
| 195 // We only need to resume blocked requests if we used a valid route_id. | 102 // We only need to resume blocked requests if we used a valid route_id. |
| 196 // See CreateNewWindow. | 103 // See CreateNewWindow. |
| 197 if (route_id != MSG_ROUTING_NONE) { | 104 if (route_id != MSG_ROUTING_NONE) { |
| 198 BrowserThread::PostTask( | 105 BrowserThread::PostTask( |
| 199 BrowserThread::IO, FROM_HERE, | 106 BrowserThread::IO, FROM_HERE, |
| 200 base::Bind(&RenderWidgetHelper::OnResumeRequestsForView, | 107 base::Bind(&RenderWidgetHelper::OnResumeRequestsForView, |
| 201 this, route_id)); | 108 this, route_id)); |
| 202 } | 109 } |
| 203 } | 110 } |
| 204 | 111 |
| 205 void RenderWidgetHelper::DidReceiveBackingStoreMsg(const IPC::Message& msg) { | |
| 206 int render_widget_id = msg.routing_id(); | |
| 207 | |
| 208 BackingStoreMsgProxy* proxy = new BackingStoreMsgProxy(this, msg); | |
| 209 { | |
| 210 base::AutoLock lock(pending_paints_lock_); | |
| 211 | |
| 212 pending_paints_[render_widget_id].push_back(proxy); | |
| 213 } | |
| 214 | |
| 215 // Notify anyone waiting on the UI thread that there is a new entry in the | |
| 216 // proxy map. If they don't find the entry they are looking for, then they | |
| 217 // will just continue waiting. | |
| 218 event_.Signal(); | |
| 219 | |
| 220 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 221 base::Bind(&BackingStoreMsgProxy::Run, base::Owned(proxy))); | |
| 222 } | |
| 223 | |
| 224 void RenderWidgetHelper::OnDiscardBackingStoreMsg(BackingStoreMsgProxy* proxy) { | |
| 225 const IPC::Message& msg = proxy->message(); | |
| 226 | |
| 227 // Remove the proxy from the map now that we are going to handle it normally. | |
| 228 { | |
| 229 base::AutoLock lock(pending_paints_lock_); | |
| 230 | |
| 231 BackingStoreMsgProxyMap::iterator it = | |
| 232 pending_paints_.find(msg.routing_id()); | |
| 233 DCHECK(it != pending_paints_.end()); | |
| 234 BackingStoreMsgProxyQueue &queue = it->second; | |
| 235 DCHECK(queue.front() == proxy); | |
| 236 | |
| 237 queue.pop_front(); | |
| 238 if (queue.empty()) | |
| 239 pending_paints_.erase(it); | |
| 240 } | |
| 241 } | |
| 242 | |
| 243 void RenderWidgetHelper::OnDispatchBackingStoreMsg( | |
| 244 BackingStoreMsgProxy* proxy) { | |
| 245 OnDiscardBackingStoreMsg(proxy); | |
| 246 | |
| 247 // It is reasonable for the host to no longer exist. | |
| 248 RenderProcessHost* host = RenderProcessHost::FromID(render_process_id_); | |
| 249 if (host) | |
| 250 host->OnMessageReceived(proxy->message()); | |
| 251 } | |
| 252 | |
| 253 void RenderWidgetHelper::OnResumeDeferredNavigation( | 112 void RenderWidgetHelper::OnResumeDeferredNavigation( |
| 254 const GlobalRequestID& request_id) { | 113 const GlobalRequestID& request_id) { |
| 255 resource_dispatcher_host_->ResumeDeferredNavigation(request_id); | 114 resource_dispatcher_host_->ResumeDeferredNavigation(request_id); |
| 256 } | 115 } |
| 257 | 116 |
| 258 void RenderWidgetHelper::OnResumeResponseDeferredAtStart( | 117 void RenderWidgetHelper::OnResumeResponseDeferredAtStart( |
| 259 const GlobalRequestID& request_id) { | 118 const GlobalRequestID& request_id) { |
| 260 resource_dispatcher_host_->ResumeResponseDeferredAtStart(request_id); | 119 resource_dispatcher_host_->ResumeResponseDeferredAtStart(request_id); |
| 261 } | 120 } |
| 262 | 121 |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 i = allocated_dibs_.begin(); i != allocated_dibs_.end(); ++i) { | 256 i = allocated_dibs_.begin(); i != allocated_dibs_.end(); ++i) { |
| 398 if (IGNORE_EINTR(close(i->second)) < 0) | 257 if (IGNORE_EINTR(close(i->second)) < 0) |
| 399 PLOG(ERROR) << "close: " << i->first; | 258 PLOG(ERROR) << "close: " << i->first; |
| 400 } | 259 } |
| 401 | 260 |
| 402 allocated_dibs_.clear(); | 261 allocated_dibs_.clear(); |
| 403 } | 262 } |
| 404 #endif | 263 #endif |
| 405 | 264 |
| 406 } // namespace content | 265 } // namespace content |
| OLD | NEW |