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 |