summaryrefslogtreecommitdiffstats
path: root/ppapi/shared_impl/resource_tracker.cc
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-18 15:41:01 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-18 15:41:01 +0000
commit7f8b26b5f223689de7af4803bc07e1e953ff5953 (patch)
treed6f3e574d97c6253b8b202264fe23dea1b489dc2 /ppapi/shared_impl/resource_tracker.cc
parentd8886526085a42874663be638be1421e78f6172c (diff)
downloadchromium_src-7f8b26b5f223689de7af4803bc07e1e953ff5953.zip
chromium_src-7f8b26b5f223689de7af4803bc07e1e953ff5953.tar.gz
chromium_src-7f8b26b5f223689de7af4803bc07e1e953ff5953.tar.bz2
Add a unified resource tracker shared between the proxy and the impl.
This renames the old ResourceObjectBase to Resource and removes the old PluginResource. It moves the resource tracker from the impl to the shared_impl, and makes the proxy use it. Some things become a little less neat because there's no proxy resource base class. In particular GetDispatcher() is now gone. I considered whether to add a helper base class that provides this function, but decided against it and had individual resource classes implement this when their implementation would find it useful. This is because ultimately I want more of this functionality to move into the shared_impl, and it's easier to do that if there are fewer proxy-specific things in the resources. This changes the way that plugins are added to the tracker. Previously they would only be in the tracker if the plugin had a reference to them, although they could be alive if the impl had a scoped_ptr referencing an object. This actually has the bug that if we then give the resource back to the plugin, it wouldn't be refcounted properly and everything would get confused. Now the tracker tracks all live resource objects whether or not the plugin has a ref. This works basically like the var tracker (it would be nice if the var and resource trackers shared more code, but that would further complicate this already overcomplicated patch). The resource tracker takes an extra ref whenever the plugin has one or more, and otherwise just tracks live resources. Review URL: http://codereview.chromium.org/7629017 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97314 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi/shared_impl/resource_tracker.cc')
-rw-r--r--ppapi/shared_impl/resource_tracker.cc162
1 files changed, 162 insertions, 0 deletions
diff --git a/ppapi/shared_impl/resource_tracker.cc b/ppapi/shared_impl/resource_tracker.cc
new file mode 100644
index 0000000..ecaa38d
--- /dev/null
+++ b/ppapi/shared_impl/resource_tracker.cc
@@ -0,0 +1,162 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ppapi/shared_impl/resource_tracker.h"
+
+#include "ppapi/shared_impl/id_assignment.h"
+#include "ppapi/shared_impl/resource.h"
+
+namespace ppapi {
+
+ResourceTracker::ResourceTracker() : last_resource_value_(0) {
+}
+
+ResourceTracker::~ResourceTracker() {
+}
+
+Resource* ResourceTracker::GetResource(PP_Resource res) const {
+ ResourceMap::const_iterator i = live_resources_.find(res);
+ if (i == live_resources_.end())
+ return NULL;
+ return i->second.first;
+}
+
+void ResourceTracker::AddRefResource(PP_Resource res) {
+ DLOG_IF(ERROR, !CheckIdType(res, PP_ID_TYPE_RESOURCE))
+ << res << " is not a PP_Resource.";
+ ResourceMap::iterator i = live_resources_.find(res);
+ if (i == live_resources_.end())
+ return;
+
+ // Prevent overflow of refcount.
+ if (i->second.second ==
+ std::numeric_limits<ResourceAndRefCount::second_type>::max())
+ return;
+
+ // When we go from 0 to 1 plugin ref count, keep an additional "real" ref
+ // on its behalf.
+ if (i->second.second == 0)
+ i->second.first->AddRef();
+
+ i->second.second++;
+ return;
+}
+
+void ResourceTracker::ReleaseResource(PP_Resource res) {
+ DLOG_IF(ERROR, !CheckIdType(res, PP_ID_TYPE_RESOURCE))
+ << res << " is not a PP_Resource.";
+ ResourceMap::iterator i = live_resources_.find(res);
+ if (i == live_resources_.end())
+ return;
+
+ // Prevent underflow of refcount.
+ if (i->second.second == 0)
+ return;
+
+ i->second.second--;
+ if (i->second.second == 0) {
+ i->second.first->LastPluginRefWasDeleted();
+
+ // When we go from 1 to 0 plugin ref count, free the additional "real" ref
+ // on its behalf. THIS WILL MOST LIKELY RELEASE THE OBJECT AND REMOVE IT
+ // FROM OUR LIST.
+ i->second.first->Release();
+ }
+}
+
+void ResourceTracker::DidCreateInstance(PP_Instance instance) {
+ // Due to the infrastructure of some tests, the instance is registered
+ // twice in a few cases. It would be nice not to do that and assert here
+ // instead.
+ if (instance_map_.find(instance) != instance_map_.end())
+ return;
+ instance_map_[instance] = linked_ptr<InstanceData>(new InstanceData);
+}
+
+void ResourceTracker::DidDeleteInstance(PP_Instance instance) {
+ InstanceMap::iterator found_instance = instance_map_.find(instance);
+
+ // Due to the infrastructure of some tests, the instance is uyregistered
+ // twice in a few cases. It would be nice not to do that and assert here
+ // instead.
+ if (found_instance == instance_map_.end())
+ return;
+
+ InstanceData& data = *found_instance->second;
+
+ // Force release all plugin references to resources associated with the
+ // deleted instance. Make a copy since as we iterate through them, each one
+ // will remove itself from the tracking info individually.
+ ResourceSet to_delete = data.resources;
+ ResourceSet::iterator cur = to_delete.begin();
+ while (cur != to_delete.end()) {
+ // Note that it's remotely possible for the object to already be deleted
+ // from the live resources. One case is if a resource object is holding
+ // the last ref to another. When we release the first one, it will release
+ // the second one. So the second one will be gone when we eventually get
+ // to it.
+ ResourceMap::iterator found_resource = live_resources_.find(*cur);
+ if (found_resource != live_resources_.end()) {
+ Resource* resource = found_resource->second.first;
+ if (found_resource->second.second > 0) {
+ resource->LastPluginRefWasDeleted();
+ found_resource->second.second = 0;
+
+ // This will most likely delete the resource object and remove it
+ // from the live_resources_ list.
+ resource->Release();
+ }
+ }
+
+ cur++;
+ }
+
+ // In general the above pass will delete all the resources and there won't
+ // be any left in the map. However, if parts of the implementation are still
+ // holding on to internal refs, we need to tell them that the instance is
+ // gone.
+ to_delete = data.resources;
+ cur = to_delete.begin();
+ while (cur != to_delete.end()) {
+ ResourceMap::iterator found_resource = live_resources_.find(*cur);
+ if (found_resource != live_resources_.end())
+ found_resource->second.first->InstanceWasDeleted();
+ cur++;
+ }
+
+ instance_map_.erase(instance);
+}
+
+int ResourceTracker::GetLiveObjectsForInstance(PP_Instance instance) const {
+ InstanceMap::const_iterator found = instance_map_.find(instance);
+ if (found == instance_map_.end())
+ return 0;
+ return static_cast<int>(found->second->resources.size());
+}
+
+PP_Resource ResourceTracker::AddResource(Resource* object) {
+ // If the plugin manages to create too many resources, don't do crazy stuff.
+ if (last_resource_value_ == kMaxPPId)
+ return 0;
+
+ // If you hit this somebody forgot to call DidCreateInstance or the resource
+ // was created with an invalid PP_Instance.
+ DCHECK(instance_map_.find(object->pp_instance()) != instance_map_.end());
+
+ PP_Resource new_id = MakeTypedId(++last_resource_value_, PP_ID_TYPE_RESOURCE);
+ instance_map_[object->pp_instance()]->resources.insert(new_id);
+
+ live_resources_[new_id] = ResourceAndRefCount(object, 0);
+ return new_id;
+}
+
+void ResourceTracker::RemoveResource(Resource* object) {
+ PP_Resource pp_resource = object->pp_resource();
+ if (object->pp_instance())
+ instance_map_[object->pp_instance()]->resources.erase(pp_resource);
+ live_resources_.erase(pp_resource);
+}
+
+
+} // namespace ppapi