Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(385)

Side by Side Diff: webkit/plugins/ppapi/resource_tracker.cc

Issue 7629017: Add a unified resource tracker shared between the proxy and the impl. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address review comments Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "webkit/plugins/ppapi/resource_tracker.h" 5 #include "webkit/plugins/ppapi/resource_tracker.h"
6 6
7 #include <limits> 7 #include <limits>
8 #include <set> 8 #include <set>
9 9
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 43
44 typedef std::map<NPObject*, NPObjectVar*> NPObjectToNPObjectVarMap; 44 typedef std::map<NPObject*, NPObjectVar*> NPObjectToNPObjectVarMap;
45 45
46 struct ResourceTracker::InstanceData { 46 struct ResourceTracker::InstanceData {
47 InstanceData() : instance(0) {} 47 InstanceData() : instance(0) {}
48 48
49 // Non-owning pointer to the instance object. When a PluginInstance is 49 // Non-owning pointer to the instance object. When a PluginInstance is
50 // destroyed, it will notify us and we'll delete all associated data. 50 // destroyed, it will notify us and we'll delete all associated data.
51 PluginInstance* instance; 51 PluginInstance* instance;
52 52
53 // Resources associated with the instance.
54 ResourceSet ref_resources;
55 std::set<Resource*> assoc_resources;
56
57 // Tracks all live NPObjectVars used by this module so we can map NPObjects 53 // Tracks all live NPObjectVars used by this module so we can map NPObjects
58 // to the corresponding object, and also release these properly if the 54 // to the corresponding object, and also release these properly if the
59 // instance goes away when there are still refs. These are non-owning 55 // instance goes away when there are still refs. These are non-owning
60 // references. 56 // references.
61 NPObjectToNPObjectVarMap np_object_to_object_var; 57 NPObjectToNPObjectVarMap np_object_to_object_var;
62 58
63 // Lazily allocated function proxies for the different interfaces. 59 // Lazily allocated function proxies for the different interfaces.
64 scoped_ptr< ::ppapi::FunctionGroupBase > 60 scoped_ptr< ::ppapi::FunctionGroupBase >
65 function_proxies[::pp::proxy::INTERFACE_ID_COUNT]; 61 function_proxies[::pp::proxy::INTERFACE_ID_COUNT];
66 }; 62 };
67 63
68 scoped_refptr<Resource> ResourceTracker::GetResource(PP_Resource res) const {
69 DLOG_IF(ERROR, !CheckIdType(res, ::ppapi::PP_ID_TYPE_RESOURCE))
70 << res << " is not a PP_Resource.";
71 ResourceMap::const_iterator result = live_resources_.find(res);
72 if (result == live_resources_.end()) {
73 return scoped_refptr<Resource>();
74 }
75 return result->second.first;
76 }
77
78 // static 64 // static
79 ResourceTracker* ResourceTracker::global_tracker_ = NULL; 65 ResourceTracker* ResourceTracker::global_tracker_ = NULL;
80 ResourceTracker* ResourceTracker::singleton_override_ = NULL; 66 ResourceTracker* ResourceTracker::singleton_override_ = NULL;
81 67
82 ResourceTracker::ResourceTracker() 68 ResourceTracker::ResourceTracker()
83 : last_resource_id_(0) { 69 : last_resource_id_(0) {
84 // Wire up the new shared resource tracker base to use our implementation. 70 // Wire up the new shared resource tracker base to use our implementation.
85 ::ppapi::TrackerBase::Init(&GetTrackerBase); 71 ::ppapi::TrackerBase::Init(&GetTrackerBase);
86 } 72 }
87 73
88 ResourceTracker::~ResourceTracker() { 74 ResourceTracker::~ResourceTracker() {
89 } 75 }
90 76
91 // static 77 // static
92 ResourceTracker* ResourceTracker::Get() { 78 ResourceTracker* ResourceTracker::Get() {
93 if (singleton_override_) 79 if (singleton_override_)
94 return singleton_override_; 80 return singleton_override_;
95 if (!global_tracker_) 81 if (!global_tracker_)
96 global_tracker_ = new ResourceTracker; 82 global_tracker_ = new ResourceTracker;
97 return global_tracker_; 83 return global_tracker_;
98 } 84 }
99 85
100 void ResourceTracker::ResourceCreated(Resource* resource,
101 PluginInstance* instance) {
102 if (!instance)
103 return;
104 PP_Instance pp_instance = instance->pp_instance();
105 DCHECK(pp_instance);
106 DCHECK(instance_map_.find(pp_instance) != instance_map_.end());
107 instance_map_[pp_instance]->assoc_resources.insert(resource);
108 }
109
110 void ResourceTracker::ResourceDestroyed(Resource* resource) {
111 if (!resource->instance())
112 return;
113
114 PP_Instance pp_instance = resource->instance()->pp_instance();
115 DCHECK(pp_instance);
116 DCHECK(instance_map_.find(pp_instance) != instance_map_.end());
117
118 instance_map_[pp_instance]->assoc_resources.erase(resource);
119 }
120
121 PP_Resource ResourceTracker::AddResource(Resource* resource) {
122 // If the plugin manages to create 1 billion resources, don't do crazy stuff.
123 if (last_resource_id_ ==
124 (std::numeric_limits<PP_Resource>::max() >> ::ppapi::kPPIdTypeBits))
125 return 0;
126
127 // Add the resource with plugin use-count 1.
128 PP_Resource new_id = MakeTypedId(++last_resource_id_,
129 ::ppapi::PP_ID_TYPE_RESOURCE);
130 live_resources_.insert(std::make_pair(new_id, std::make_pair(resource, 1)));
131
132 // Track associated with the instance.
133 PP_Instance pp_instance = resource->instance()->pp_instance();
134 DCHECK(instance_map_.find(pp_instance) != instance_map_.end());
135 instance_map_[pp_instance]->ref_resources.insert(new_id);
136 return new_id;
137 }
138
139 bool ResourceTracker::AddRefResource(PP_Resource res) {
140 DLOG_IF(ERROR, !CheckIdType(res, ::ppapi::PP_ID_TYPE_RESOURCE))
141 << res << " is not a PP_Resource.";
142 ResourceMap::iterator i = live_resources_.find(res);
143 if (i != live_resources_.end()) {
144 // We don't protect against overflow, since a plugin as malicious as to ref
145 // once per every byte in the address space could have just as well unrefed
146 // one time too many.
147 ++i->second.second;
148 return true;
149 } else {
150 return false;
151 }
152 }
153
154 bool ResourceTracker::UnrefResource(PP_Resource res) {
155 DLOG_IF(ERROR, !CheckIdType(res, ::ppapi::PP_ID_TYPE_RESOURCE))
156 << res << " is not a PP_Resource.";
157 ResourceMap::iterator i = live_resources_.find(res);
158 if (i != live_resources_.end()) {
159 if (!--i->second.second) {
160 Resource* to_release = i->second.first;
161 // LastPluginRefWasDeleted will clear the instance pointer, so save it
162 // first.
163 PP_Instance instance = to_release->instance()->pp_instance();
164 to_release->LastPluginRefWasDeleted();
165
166 instance_map_[instance]->ref_resources.erase(res);
167 live_resources_.erase(i);
168 }
169 return true;
170 } else {
171 return false;
172 }
173 }
174
175 void ResourceTracker::CleanupInstanceData(PP_Instance instance, 86 void ResourceTracker::CleanupInstanceData(PP_Instance instance,
176 bool delete_instance) { 87 bool delete_instance) {
177 DLOG_IF(ERROR, !CheckIdType(instance, ::ppapi::PP_ID_TYPE_INSTANCE)) 88 DLOG_IF(ERROR, !CheckIdType(instance, ::ppapi::PP_ID_TYPE_INSTANCE))
178 << instance << " is not a PP_Instance."; 89 << instance << " is not a PP_Instance.";
179 InstanceMap::iterator found = instance_map_.find(instance); 90 InstanceMap::iterator found = instance_map_.find(instance);
180 if (found == instance_map_.end()) { 91 if (found == instance_map_.end()) {
181 NOTREACHED(); 92 NOTREACHED();
182 return; 93 return;
183 } 94 }
184 InstanceData& data = *found->second; 95 InstanceData& data = *found->second;
185 96
186 // Force release all plugin references to resources associated with the
187 // deleted instance.
188 ResourceSet::iterator cur_res = data.ref_resources.begin();
189 while (cur_res != data.ref_resources.end()) {
190 ResourceMap::iterator found_resource = live_resources_.find(*cur_res);
191 if (found_resource == live_resources_.end()) {
192 NOTREACHED();
193 } else {
194 Resource* resource = found_resource->second.first;
195
196 // Must delete from the resource set first since the resource's instance
197 // pointer will get zeroed out in LastPluginRefWasDeleted.
198 resource->LastPluginRefWasDeleted();
199 live_resources_.erase(*cur_res);
200 }
201
202 // Iterators to a set are stable so we can iterate the set while the items
203 // are being deleted as long as we're careful not to delete the item we're
204 // holding an iterator to.
205 ResourceSet::iterator current = cur_res++;
206 data.ref_resources.erase(current);
207 }
208 DCHECK(data.ref_resources.empty());
209
210 // Force delete all var references. Need to make a copy so we can iterate over 97 // Force delete all var references. Need to make a copy so we can iterate over
211 // the map while deleting stuff from it. 98 // the map while deleting stuff from it.
212 NPObjectToNPObjectVarMap np_object_map_copy = data.np_object_to_object_var; 99 NPObjectToNPObjectVarMap np_object_map_copy = data.np_object_to_object_var;
213 NPObjectToNPObjectVarMap::iterator cur_var = 100 NPObjectToNPObjectVarMap::iterator cur_var =
214 np_object_map_copy.begin(); 101 np_object_map_copy.begin();
215 while (cur_var != np_object_map_copy.end()) { 102 while (cur_var != np_object_map_copy.end()) {
216 NPObjectToNPObjectVarMap::iterator current = cur_var++; 103 NPObjectToNPObjectVarMap::iterator current = cur_var++;
217 104
218 // Clear the object from the var mapping and the live instance object list. 105 // Clear the object from the var mapping and the live instance object list.
219 int32 var_id = current->second->GetExistingVarID(); 106 int32 var_id = current->second->GetExistingVarID();
220 if (var_id) 107 if (var_id)
221 live_vars_.erase(var_id); 108 live_vars_.erase(var_id);
222 109
223 current->second->InstanceDeleted(); 110 current->second->InstanceDeleted();
224 data.np_object_to_object_var.erase(current->first); 111 data.np_object_to_object_var.erase(current->first);
225 } 112 }
226 DCHECK(data.np_object_to_object_var.empty()); 113 DCHECK(data.np_object_to_object_var.empty());
227 114
228 // Clear any resources that still reference this instance.
229 for (std::set<Resource*>::iterator res = data.assoc_resources.begin();
230 res != data.assoc_resources.end();
231 ++res)
232 (*res)->ClearInstance();
233 data.assoc_resources.clear();
234
235 if (delete_instance) 115 if (delete_instance)
236 instance_map_.erase(found); 116 instance_map_.erase(found);
237 } 117 }
238 118
239 uint32 ResourceTracker::GetLiveObjectsForInstance(
240 PP_Instance instance) const {
241 InstanceMap::const_iterator found = instance_map_.find(instance);
242 if (found == instance_map_.end())
243 return 0;
244 return static_cast<uint32>(found->second->ref_resources.size() +
245 found->second->np_object_to_object_var.size());
246 }
247
248 ::ppapi::ResourceObjectBase* ResourceTracker::GetResourceAPI(
249 PP_Resource res) {
250 DLOG_IF(ERROR, !CheckIdType(res, ::ppapi::PP_ID_TYPE_RESOURCE))
251 << res << " is not a PP_Resource.";
252 ResourceMap::const_iterator result = live_resources_.find(res);
253 if (result == live_resources_.end())
254 return NULL;
255 return result->second.first.get();
256 }
257
258 ::ppapi::FunctionGroupBase* ResourceTracker::GetFunctionAPI( 119 ::ppapi::FunctionGroupBase* ResourceTracker::GetFunctionAPI(
259 PP_Instance pp_instance, 120 PP_Instance pp_instance,
260 pp::proxy::InterfaceID id) { 121 pp::proxy::InterfaceID id) {
261 // Get the instance object. This also ensures that the instance data is in 122 // Get the instance object. This also ensures that the instance data is in
262 // the map, since we need it below. 123 // the map, since we need it below.
263 PluginInstance* instance = GetInstance(pp_instance); 124 PluginInstance* instance = GetInstance(pp_instance);
264 if (!instance) 125 if (!instance)
265 return NULL; 126 return NULL;
266 127
267 // The instance one is special, since it's just implemented by the instance 128 // The instance one is special, since it's just implemented by the instance
(...skipping 22 matching lines...) Expand all
290 case pp::proxy::INTERFACE_ID_RESOURCE_CREATION: 151 case pp::proxy::INTERFACE_ID_RESOURCE_CREATION:
291 proxy.reset(new ResourceCreationImpl(instance)); 152 proxy.reset(new ResourceCreationImpl(instance));
292 break; 153 break;
293 default: 154 default:
294 NOTREACHED(); 155 NOTREACHED();
295 } 156 }
296 157
297 return proxy.get(); 158 return proxy.get();
298 } 159 }
299 160
300 PP_Instance ResourceTracker::GetInstanceForResource(PP_Resource pp_resource) {
301 scoped_refptr<Resource> resource(GetResource(pp_resource));
302 if (!resource.get())
303 return 0;
304 return resource->instance()->pp_instance();
305 }
306
307 ::ppapi::VarTracker* ResourceTracker::GetVarTracker() { 161 ::ppapi::VarTracker* ResourceTracker::GetVarTracker() {
308 return &var_tracker_; 162 return &var_tracker_;
309 } 163 }
310 164
165 ::ppapi::ResourceTracker* ResourceTracker::GetResourceTracker() {
166 return this;
167 }
168
311 void ResourceTracker::AddNPObjectVar(NPObjectVar* object_var) { 169 void ResourceTracker::AddNPObjectVar(NPObjectVar* object_var) {
312 DCHECK(instance_map_.find(object_var->pp_instance()) != instance_map_.end()); 170 DCHECK(instance_map_.find(object_var->pp_instance()) != instance_map_.end());
313 InstanceData& data = *instance_map_[object_var->pp_instance()].get(); 171 InstanceData& data = *instance_map_[object_var->pp_instance()].get();
314 172
315 DCHECK(data.np_object_to_object_var.find(object_var->np_object()) == 173 DCHECK(data.np_object_to_object_var.find(object_var->np_object()) ==
316 data.np_object_to_object_var.end()) << "NPObjectVar already in map"; 174 data.np_object_to_object_var.end()) << "NPObjectVar already in map";
317 data.np_object_to_object_var[object_var->np_object()] = object_var; 175 data.np_object_to_object_var[object_var->np_object()] = object_var;
318 } 176 }
319 177
320 void ResourceTracker::RemoveNPObjectVar(NPObjectVar* object_var) { 178 void ResourceTracker::RemoveNPObjectVar(NPObjectVar* object_var) {
(...skipping 18 matching lines...) Expand all
339 DCHECK(instance_map_.find(instance) != instance_map_.end()); 197 DCHECK(instance_map_.find(instance) != instance_map_.end());
340 InstanceData& data = *instance_map_[instance].get(); 198 InstanceData& data = *instance_map_[instance].get();
341 199
342 NPObjectToNPObjectVarMap::iterator found = 200 NPObjectToNPObjectVarMap::iterator found =
343 data.np_object_to_object_var.find(np_object); 201 data.np_object_to_object_var.find(np_object);
344 if (found == data.np_object_to_object_var.end()) 202 if (found == data.np_object_to_object_var.end())
345 return NULL; 203 return NULL;
346 return found->second; 204 return found->second;
347 } 205 }
348 206
207 int ResourceTracker::GetLiveNPObjectVarsForInstance(
208 PP_Instance instance) const {
209 InstanceMap::const_iterator found = instance_map_.find(instance);
210 if (found == instance_map_.end())
211 return 0;
212 return static_cast<int>(found->second->np_object_to_object_var.size());
213 }
214
349 PP_Instance ResourceTracker::AddInstance(PluginInstance* instance) { 215 PP_Instance ResourceTracker::AddInstance(PluginInstance* instance) {
350 DCHECK(instance_map_.find(instance->pp_instance()) == instance_map_.end()); 216 DCHECK(instance_map_.find(instance->pp_instance()) == instance_map_.end());
351 217
352 // Use a random number for the instance ID. This helps prevent some 218 // Use a random number for the instance ID. This helps prevent some
353 // accidents. See also AddModule below. 219 // accidents. See also AddModule below.
354 // 220 //
355 // Need to make sure the random number isn't a duplicate or 0. 221 // Need to make sure the random number isn't a duplicate or 0.
356 PP_Instance new_instance; 222 PP_Instance new_instance;
357 do { 223 do {
358 new_instance = MakeTypedId(static_cast<PP_Instance>(base::RandUint64()), 224 new_instance = MakeTypedId(static_cast<PP_Instance>(base::RandUint64()),
359 ::ppapi::PP_ID_TYPE_INSTANCE); 225 ::ppapi::PP_ID_TYPE_INSTANCE);
360 } while (!new_instance || 226 } while (!new_instance ||
361 instance_map_.find(new_instance) != instance_map_.end() || 227 instance_map_.find(new_instance) != instance_map_.end() ||
362 !instance->module()->ReserveInstanceID(new_instance)); 228 !instance->module()->ReserveInstanceID(new_instance));
363 229
364 instance_map_[new_instance] = linked_ptr<InstanceData>(new InstanceData); 230 instance_map_[new_instance] = linked_ptr<InstanceData>(new InstanceData);
365 instance_map_[new_instance]->instance = instance; 231 instance_map_[new_instance]->instance = instance;
232
233 DidCreateInstance(new_instance);
366 return new_instance; 234 return new_instance;
367 } 235 }
368 236
369 void ResourceTracker::InstanceDeleted(PP_Instance instance) { 237 void ResourceTracker::InstanceDeleted(PP_Instance instance) {
238 DidDeleteInstance(instance);
370 CleanupInstanceData(instance, true); 239 CleanupInstanceData(instance, true);
371 } 240 }
372 241
373 void ResourceTracker::InstanceCrashed(PP_Instance instance) { 242 void ResourceTracker::InstanceCrashed(PP_Instance instance) {
243 DidDeleteInstance(instance);
374 CleanupInstanceData(instance, false); 244 CleanupInstanceData(instance, false);
375 } 245 }
376 246
377 PluginInstance* ResourceTracker::GetInstance(PP_Instance instance) { 247 PluginInstance* ResourceTracker::GetInstance(PP_Instance instance) {
378 DLOG_IF(ERROR, !CheckIdType(instance, ::ppapi::PP_ID_TYPE_INSTANCE)) 248 DLOG_IF(ERROR, !CheckIdType(instance, ::ppapi::PP_ID_TYPE_INSTANCE))
379 << instance << " is not a PP_Instance."; 249 << instance << " is not a PP_Instance.";
380 InstanceMap::iterator found = instance_map_.find(instance); 250 InstanceMap::iterator found = instance_map_.find(instance);
381 if (found == instance_map_.end()) 251 if (found == instance_map_.end())
382 return NULL; 252 return NULL;
383 return found->second->instance; 253 return found->second->instance;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 300
431 // static 301 // static
432 void ResourceTracker::ClearSingletonOverride() { 302 void ResourceTracker::ClearSingletonOverride() {
433 DCHECK(singleton_override_); 303 DCHECK(singleton_override_);
434 singleton_override_ = NULL; 304 singleton_override_ = NULL;
435 } 305 }
436 306
437 } // namespace ppapi 307 } // namespace ppapi
438 } // namespace webkit 308 } // namespace webkit
439 309
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698