summaryrefslogtreecommitdiffstats
path: root/ppapi/shared_impl
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
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')
-rw-r--r--ppapi/shared_impl/audio_config_impl.h2
-rw-r--r--ppapi/shared_impl/audio_impl.h2
-rw-r--r--ppapi/shared_impl/resource.cc54
-rw-r--r--ppapi/shared_impl/resource.h141
-rw-r--r--ppapi/shared_impl/resource_object_base.cc26
-rw-r--r--ppapi/shared_impl/resource_object_base.h93
-rw-r--r--ppapi/shared_impl/resource_tracker.cc162
-rw-r--r--ppapi/shared_impl/resource_tracker.h93
-rw-r--r--ppapi/shared_impl/resource_tracker_unittest.cc148
-rw-r--r--ppapi/shared_impl/tracker_base.h11
-rw-r--r--ppapi/shared_impl/video_decoder_impl.cc5
-rw-r--r--ppapi/shared_impl/video_decoder_impl.h7
12 files changed, 606 insertions, 138 deletions
diff --git a/ppapi/shared_impl/audio_config_impl.h b/ppapi/shared_impl/audio_config_impl.h
index 230856f..079df76 100644
--- a/ppapi/shared_impl/audio_config_impl.h
+++ b/ppapi/shared_impl/audio_config_impl.h
@@ -7,7 +7,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
-#include "ppapi/shared_impl/resource_object_base.h"
+#include "ppapi/shared_impl/resource.h"
#include "ppapi/thunk/ppb_audio_config_api.h"
namespace ppapi {
diff --git a/ppapi/shared_impl/audio_impl.h b/ppapi/shared_impl/audio_impl.h
index a640d37..220962bb 100644
--- a/ppapi/shared_impl/audio_impl.h
+++ b/ppapi/shared_impl/audio_impl.h
@@ -10,7 +10,7 @@
#include "base/sync_socket.h"
#include "base/threading/simple_thread.h"
#include "ppapi/c/ppb_audio.h"
-#include "ppapi/shared_impl/resource_object_base.h"
+#include "ppapi/shared_impl/resource.h"
#include "ppapi/thunk/ppb_audio_api.h"
namespace ppapi {
diff --git a/ppapi/shared_impl/resource.cc b/ppapi/shared_impl/resource.cc
new file mode 100644
index 0000000..11ac86a
--- /dev/null
+++ b/ppapi/shared_impl/resource.cc
@@ -0,0 +1,54 @@
+// 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.h"
+
+#include "base/logging.h"
+#include "ppapi/shared_impl/resource_tracker.h"
+#include "ppapi/shared_impl/tracker_base.h"
+
+namespace ppapi {
+
+Resource::Resource(PP_Instance instance) {
+ // The instance should always be valid (nonzero).
+ DCHECK(instance);
+
+ // For the in-process case, the host resource and resource are the same.
+ //
+ // AddResource needs our instance() getter to work, and that goes through
+ // the host resource, so we need to fill that first even though we don't
+ // have a resource ID yet, then fill the resource in later.
+ host_resource_ = HostResource::MakeInstanceOnly(instance);
+ pp_resource_ = TrackerBase::Get()->GetResourceTracker()->AddResource(this);
+ host_resource_.SetHostResource(instance, pp_resource_);
+}
+
+Resource::Resource(const HostResource& host_resource)
+ : host_resource_(host_resource) {
+ pp_resource_ = TrackerBase::Get()->GetResourceTracker()->AddResource(this);
+}
+
+Resource::~Resource() {
+ TrackerBase::Get()->GetResourceTracker()->RemoveResource(this);
+}
+
+PP_Resource Resource::GetReference() {
+ TrackerBase::Get()->GetResourceTracker()->AddRefResource(pp_resource());
+ return pp_resource();
+}
+
+void Resource::LastPluginRefWasDeleted() {
+}
+
+void Resource::InstanceWasDeleted() {
+ host_resource_ = HostResource();
+}
+
+#define DEFINE_TYPE_GETTER(RESOURCE) \
+ thunk::RESOURCE* Resource::As##RESOURCE() { return NULL; }
+FOR_ALL_PPAPI_RESOURCE_APIS(DEFINE_TYPE_GETTER)
+#undef DEFINE_TYPE_GETTER
+
+} // namespace ppapi
+
diff --git a/ppapi/shared_impl/resource.h b/ppapi/shared_impl/resource.h
new file mode 100644
index 0000000..6bb4099
--- /dev/null
+++ b/ppapi/shared_impl/resource.h
@@ -0,0 +1,141 @@
+// 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.
+
+#ifndef PPAPI_SHARED_IMPL_RESOURCE_H_
+#define PPAPI_SHARED_IMPL_RESOURCE_H_
+
+#include <stddef.h> // For NULL.
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "ppapi/c/pp_instance.h"
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/shared_impl/host_resource.h"
+
+// All resource types should be added here. This implements our hand-rolled
+// RTTI system since we don't compile with "real" RTTI.
+#define FOR_ALL_PPAPI_RESOURCE_APIS(F) \
+ F(PPB_AudioConfig_API) \
+ F(PPB_AudioTrusted_API) \
+ F(PPB_Audio_API) \
+ F(PPB_Broker_API) \
+ F(PPB_Buffer_API) \
+ F(PPB_BufferTrusted_API) \
+ F(PPB_Context3D_API) \
+ F(PPB_DirectoryReader_API) \
+ F(PPB_FileChooser_API) \
+ F(PPB_FileIO_API) \
+ F(PPB_FileRef_API) \
+ F(PPB_FileSystem_API) \
+ F(PPB_Find_API) \
+ F(PPB_Flash_Menu_API) \
+ F(PPB_Flash_NetConnector_API) \
+ F(PPB_Flash_TCPSocket_API) \
+ F(PPB_Font_API) \
+ F(PPB_Graphics2D_API) \
+ F(PPB_Graphics3D_API) \
+ F(PPB_ImageData_API) \
+ F(PPB_InputEvent_API) \
+ F(PPB_LayerCompositor_API) \
+ F(PPB_PDFFont_API) \
+ F(PPB_Scrollbar_API) \
+ F(PPB_Surface3D_API) \
+ F(PPB_Transport_API) \
+ F(PPB_URLLoader_API) \
+ F(PPB_URLRequestInfo_API) \
+ F(PPB_URLResponseInfo_API) \
+ F(PPB_VideoCapture_API) \
+ F(PPB_VideoDecoder_API) \
+ F(PPB_VideoLayer_API) \
+ F(PPB_Widget_API)
+
+namespace ppapi {
+
+// Forward declare all the resource APIs.
+namespace thunk {
+#define DECLARE_RESOURCE_CLASS(RESOURCE) class RESOURCE;
+FOR_ALL_PPAPI_RESOURCE_APIS(DECLARE_RESOURCE_CLASS)
+#undef DECLARE_RESOURCE_CLASS
+} // namespace thunk
+
+class Resource : public base::RefCounted<Resource> {
+ public:
+ // For constructing non-proxied objects. This just takes the associated
+ // instance, and generates a new resource ID. The host resource will be the
+ // same as the newly-generated resource ID.
+ explicit Resource(PP_Instance instance);
+
+ // For constructing proxied objects. This takes the resource generated in
+ // the host side, stores it, and allocates a "local" resource ID for use in
+ // the current process.
+ explicit Resource(const HostResource& host_resource);
+
+ virtual ~Resource();
+
+ PP_Instance pp_instance() const { return host_resource_.instance(); }
+
+ // Returns the resource ID for this object in the current process without
+ // adjusting the refcount. See also GetReference().
+ PP_Resource pp_resource() const { return pp_resource_; }
+
+ // Returns the host resource which identifies the resource in the host side
+ // of the process in the case of proxied objects. For in-process objects,
+ // this just identifies the in-process resource ID & instance.
+ const HostResource& host_resource() { return host_resource_; }
+
+ // Adds a ref on behalf of the plugin and returns the resource ID. This is
+ // normally used when returning a resource to the plugin, where it's
+ // expecting the returned resource to have ownership of a ref passed.
+ // See also pp_resource() to avoid the AddRef.
+ PP_Resource GetReference();
+
+ // Called by the resource tracker when the last reference from the plugin
+ // was released. For a few types of resources, the resource could still
+ // stay alive if there are other references held by the PPAPI implementation
+ // (possibly for callbacks and things).
+ virtual void LastPluginRefWasDeleted();
+
+ // Called by the resource tracker when the instance is going away but the
+ // object is still alive (this is not the common case, since it requires
+ // something in the implementation to be keeping a ref that keeps the
+ // resource alive.
+ //
+ // You will want to override this if your resource does some kind of
+ // background processing (like maybe network loads) on behalf of the plugin
+ // and you want to stop that when the plugin is deleted.
+ //
+ // Be sure to call this version which clears the instance ID.
+ virtual void InstanceWasDeleted();
+
+ // Dynamic casting for this object. Returns the pointer to the given type if
+ // it's supported. Derived classes override the functions they support to
+ // return the interface.
+ #define DEFINE_TYPE_GETTER(RESOURCE) \
+ virtual thunk::RESOURCE* As##RESOURCE();
+ FOR_ALL_PPAPI_RESOURCE_APIS(DEFINE_TYPE_GETTER)
+ #undef DEFINE_TYPE_GETTER
+
+ // Template-based dynamic casting. See specializations below.
+ template <typename T> T* GetAs() { return NULL; }
+
+ private:
+ // See the getters above.
+ PP_Resource pp_resource_;
+ HostResource host_resource_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Resource);
+};
+
+// Template-based dynamic casting. These specializations forward to the
+// AsXXX virtual functions to return whether the given type is supported.
+#define DEFINE_RESOURCE_CAST(RESOURCE) \
+ template<> inline thunk::RESOURCE* Resource::GetAs() { \
+ return As##RESOURCE(); \
+ }
+FOR_ALL_PPAPI_RESOURCE_APIS(DEFINE_RESOURCE_CAST)
+#undef DEFINE_RESOURCE_CAST
+
+} // namespace ppapi
+
+#endif // PPAPI_SHARED_IMPL_RESOURCE_H_
diff --git a/ppapi/shared_impl/resource_object_base.cc b/ppapi/shared_impl/resource_object_base.cc
deleted file mode 100644
index 27ef9e9..0000000
--- a/ppapi/shared_impl/resource_object_base.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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_object_base.h"
-
-#include "base/logging.h"
-
-namespace ppapi {
-
-ResourceObjectBase::ResourceObjectBase(PP_Instance instance)
- : pp_instance_(instance) {
- // Instance should be valid (nonzero).
- DCHECK(instance);
-}
-
-ResourceObjectBase::~ResourceObjectBase() {
-}
-
-#define DEFINE_TYPE_GETTER(RESOURCE) \
- thunk::RESOURCE* ResourceObjectBase::As##RESOURCE() { return NULL; }
-FOR_ALL_PPAPI_RESOURCE_APIS(DEFINE_TYPE_GETTER)
-#undef DEFINE_TYPE_GETTER
-
-} // namespace ppapi
-
diff --git a/ppapi/shared_impl/resource_object_base.h b/ppapi/shared_impl/resource_object_base.h
deleted file mode 100644
index 3408525..0000000
--- a/ppapi/shared_impl/resource_object_base.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// 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.
-
-#ifndef PPAPI_SHARED_IMPL_RESOURCE_OBJECT_BASE_H_
-#define PPAPI_SHARED_IMPL_RESOURCE_OBJECT_BASE_H_
-
-#include <stddef.h> // For NULL.
-
-#include "base/memory/ref_counted.h"
-#include "ppapi/c/pp_instance.h"
-
-#define FOR_ALL_PPAPI_RESOURCE_APIS(F) \
- F(PPB_AudioConfig_API) \
- F(PPB_AudioTrusted_API) \
- F(PPB_Audio_API) \
- F(PPB_Broker_API) \
- F(PPB_Buffer_API) \
- F(PPB_BufferTrusted_API) \
- F(PPB_Context3D_API) \
- F(PPB_DirectoryReader_API) \
- F(PPB_FileChooser_API) \
- F(PPB_FileIO_API) \
- F(PPB_FileRef_API) \
- F(PPB_FileSystem_API) \
- F(PPB_Find_API) \
- F(PPB_Flash_Menu_API) \
- F(PPB_Flash_NetConnector_API) \
- F(PPB_Flash_TCPSocket_API) \
- F(PPB_Font_API) \
- F(PPB_Graphics2D_API) \
- F(PPB_Graphics3D_API) \
- F(PPB_ImageData_API) \
- F(PPB_InputEvent_API) \
- F(PPB_LayerCompositor_API) \
- F(PPB_PDFFont_API) \
- F(PPB_Scrollbar_API) \
- F(PPB_Surface3D_API) \
- F(PPB_Transport_API) \
- F(PPB_URLLoader_API) \
- F(PPB_URLRequestInfo_API) \
- F(PPB_URLResponseInfo_API) \
- F(PPB_VideoCapture_API) \
- F(PPB_VideoDecoder_API) \
- F(PPB_VideoLayer_API) \
- F(PPB_Widget_API)
-
-namespace ppapi {
-
-// Forward declare all the resource APIs.
-namespace thunk {
-#define DECLARE_RESOURCE_CLASS(RESOURCE) class RESOURCE;
-FOR_ALL_PPAPI_RESOURCE_APIS(DECLARE_RESOURCE_CLASS)
-#undef DECLARE_RESOURCE_CLASS
-} // namespace thunk
-
-class ResourceObjectBase : public base::RefCounted<ResourceObjectBase> {
- public:
- ResourceObjectBase(PP_Instance instance);
- virtual ~ResourceObjectBase();
-
- PP_Instance pp_instance() const { return pp_instance_; }
-
- // Dynamic casting for this object. Returns the pointer to the given type if
- // Inheritance-based dynamic casting for this object. Returns the pointer to
- // the given type if it's supported. Derived classes override the functions
- // they support to return the interface.
- #define DEFINE_TYPE_GETTER(RESOURCE) \
- virtual thunk::RESOURCE* As##RESOURCE();
- FOR_ALL_PPAPI_RESOURCE_APIS(DEFINE_TYPE_GETTER)
- #undef DEFINE_TYPE_GETTER
-
- // Template-based dynamic casting. See specializations below.
- template <typename T> T* GetAs() { return NULL; }
-
- private:
- PP_Instance pp_instance_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(ResourceObjectBase);
-};
-
-// Template-based dynamic casting. These specializations forward to the
-// AsXXX virtual functions to return whether the given type is supported.
-#define DEFINE_RESOURCE_CAST(RESOURCE) \
- template<> inline thunk::RESOURCE* ResourceObjectBase::GetAs() { \
- return As##RESOURCE(); \
- }
-FOR_ALL_PPAPI_RESOURCE_APIS(DEFINE_RESOURCE_CAST)
-#undef DEFINE_RESOURCE_CAST
-
-} // namespace ppapi
-
-#endif // PPAPI_SHARED_IMPL_RESOURCE_OBJECT_BASE_H_
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
diff --git a/ppapi/shared_impl/resource_tracker.h b/ppapi/shared_impl/resource_tracker.h
new file mode 100644
index 0000000..04230d9
--- /dev/null
+++ b/ppapi/shared_impl/resource_tracker.h
@@ -0,0 +1,93 @@
+// 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.
+
+#ifndef PPAPI_SHARED_IMPL_RESOURCE_TRACKER_H_
+#define PPAPI_SHARED_IMPL_RESOURCE_TRACKER_H_
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/hash_tables.h"
+#include "base/memory/linked_ptr.h"
+#include "ppapi/c/pp_instance.h"
+#include "ppapi/c/pp_resource.h"
+
+namespace ppapi {
+
+class Resource;
+
+class ResourceTracker {
+ public:
+ ResourceTracker();
+ virtual ~ResourceTracker();
+
+ // The returned pointer will be NULL if there is no resource. The reference
+ // count of the resource is unaffected.
+ Resource* GetResource(PP_Resource res) const;
+
+ void AddRefResource(PP_Resource res);
+ void ReleaseResource(PP_Resource res);
+
+ // Notifies the tracker that a new instance has been created. This must be
+ // called before creating any resources associated with the instance.
+ void DidCreateInstance(PP_Instance instance);
+
+ // Called when an instance is being deleted. All plugin refs for the
+ // associated resources will be force freed, and the resources (if they still
+ // exist) will be disassociated from the instance.
+ void DidDeleteInstance(PP_Instance instance);
+
+ // Returns the number of resources associated with the given instance.
+ // Returns 0 if the instance isn't known.
+ int GetLiveObjectsForInstance(PP_Instance instance) const;
+
+ protected:
+ // This calls AddResource and RemoveResource.
+ friend class Resource;
+
+ // Adds the given resource to the tracker, associating it with the instance
+ // stored in the resource object. The new resource ID is returned, and the
+ // resource will have 0 plugin refcount. This is called by the resource
+ // constructor.
+ //
+ // Returns 0 if the resource could not be added.
+ virtual PP_Resource AddResource(Resource* object);
+
+ // The opposite of AddResource, this removes the tracking information for
+ // the given resource. It's called from the resource destructor.
+ virtual void RemoveResource(Resource* object);
+
+ private:
+ typedef std::set<PP_Resource> ResourceSet;
+
+ struct InstanceData {
+ // Lists all resources associated with the given instance as non-owning
+ // pointers. This allows us to notify those resources that the instance is
+ // going away (otherwise, they may crash if they outlive the instance).
+ ResourceSet resources;
+ };
+ typedef base::hash_map<PP_Instance, linked_ptr<InstanceData> > InstanceMap;
+
+ InstanceMap instance_map_;
+
+ // For each PP_Resource, keep the object pointer and a plugin use count.
+ // This use count is different then Resource object's RefCount, and is
+ // manipulated using this AddRefResource/UnrefResource. When the plugin use
+ // count is positive, we keep an extra ref on the Resource on
+ // behalf of the plugin. When it drops to 0, we free that ref, keeping
+ // the resource in the list.
+ //
+ // A resource will be in this list as long as the object is alive.
+ typedef std::pair<Resource*, int> ResourceAndRefCount;
+ typedef base::hash_map<PP_Resource, ResourceAndRefCount> ResourceMap;
+ ResourceMap live_resources_;
+
+ int32 last_resource_value_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResourceTracker);
+};
+
+} // namespace ppapi
+
+#endif // PPAPI_SHARED_IMPL_RESOURCE_TRACKER_H_
diff --git a/ppapi/shared_impl/resource_tracker_unittest.cc b/ppapi/shared_impl/resource_tracker_unittest.cc
new file mode 100644
index 0000000..186b162
--- /dev/null
+++ b/ppapi/shared_impl/resource_tracker_unittest.cc
@@ -0,0 +1,148 @@
+// 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 "testing/gtest/include/gtest/gtest.h"
+
+#include "base/compiler_specific.h"
+#include "ppapi/shared_impl/resource.h"
+#include "ppapi/shared_impl/resource_tracker.h"
+#include "ppapi/shared_impl/tracker_base.h"
+
+namespace ppapi {
+
+namespace {
+
+int mock_resource_alive_count = 0;
+int last_plugin_ref_was_deleted_count = 0;
+int instance_was_deleted_count = 0;
+
+class MyMockResource : public Resource {
+ public:
+ MyMockResource(PP_Instance instance) : Resource(instance) {
+ mock_resource_alive_count++;
+ }
+ virtual ~MyMockResource() {
+ mock_resource_alive_count--;
+ }
+
+ virtual void LastPluginRefWasDeleted() OVERRIDE {
+ Resource::LastPluginRefWasDeleted();
+ last_plugin_ref_was_deleted_count++;
+ }
+ virtual void InstanceWasDeleted() OVERRIDE {
+ Resource::InstanceWasDeleted();
+ instance_was_deleted_count++;
+ }
+};
+
+// Global singleton used by the TrackerBase.
+TrackerBase* my_tracker_base = NULL;
+TrackerBase* GetMyTrackerBase() {
+ return my_tracker_base;
+}
+
+} // namespace
+
+class ResourceTrackerTest : public testing::Test, public TrackerBase {
+ public:
+ ResourceTrackerTest() {}
+
+ // Test implementation.
+ virtual void SetUp() OVERRIDE {
+ my_tracker_base = this;
+ TrackerBase::Init(&GetMyTrackerBase);
+
+ ASSERT_EQ(0, mock_resource_alive_count);
+ last_plugin_ref_was_deleted_count = 0;
+ instance_was_deleted_count = 0;
+ }
+ virtual void TearDown() OVERRIDE {
+ my_tracker_base = NULL;
+ TrackerBase::Init(NULL);
+ }
+
+ // TrackerBase implementation.
+ virtual FunctionGroupBase* GetFunctionAPI(
+ PP_Instance inst,
+ pp::proxy::InterfaceID id) OVERRIDE {
+ return NULL;
+ }
+ virtual VarTracker* GetVarTracker() OVERRIDE {
+ return NULL;
+ }
+ virtual ResourceTracker* GetResourceTracker() OVERRIDE {
+ return &resource_tracker_;
+ }
+
+ ResourceTracker& resource_tracker() { return resource_tracker_; }
+
+ private:
+ ResourceTracker resource_tracker_;
+};
+
+// Test that LastPluginRefWasDeleted is called when the last plugin ref was
+// deleted but the object lives on.
+TEST_F(ResourceTrackerTest, LastPluginRef) {
+ PP_Instance instance = 0x1234567;
+ resource_tracker().DidCreateInstance(instance);
+
+ scoped_refptr<MyMockResource> resource(new MyMockResource(instance));
+ PP_Resource pp_resource = resource->GetReference();
+ EXPECT_TRUE(resource_tracker().GetResource(pp_resource));
+
+ // Releasing it should keep the object (because we have a ref) but fire the
+ // "last plugin ref" message.
+ resource_tracker().ReleaseResource(pp_resource);
+ EXPECT_EQ(1, last_plugin_ref_was_deleted_count);
+ EXPECT_EQ(1, mock_resource_alive_count);
+
+ resource_tracker().DidDeleteInstance(instance);
+ resource = NULL;
+ EXPECT_FALSE(resource_tracker().GetResource(pp_resource));
+}
+
+// Tests when the plugin is holding a ref to a resource when the instance is
+// deleted.
+TEST_F(ResourceTrackerTest, InstanceDeletedWithPluginRef) {
+ // Make a resource with one ref held by the plugin, and delete the instance.
+ PP_Instance instance = 0x2345678;
+ resource_tracker().DidCreateInstance(instance);
+ MyMockResource* resource = new MyMockResource(instance);
+ resource->GetReference();
+ EXPECT_EQ(1, mock_resource_alive_count);
+ resource_tracker().DidDeleteInstance(instance);
+
+ // The resource should have been deleted, and before it was, it should have
+ // received a "last plugin ref was deleted" notification.
+ EXPECT_EQ(0, mock_resource_alive_count);
+ EXPECT_EQ(1, last_plugin_ref_was_deleted_count);
+ EXPECT_EQ(0, instance_was_deleted_count);
+}
+
+// Test when the plugin and the internal implementation (via scoped_refptr) is
+// holding a ref to a resource when the instance is deleted.
+TEST_F(ResourceTrackerTest, InstanceDeletedWithBothRefed) {
+ // Create a new instance.
+ PP_Instance instance = 0x3456789;
+
+ // Make a resource with one ref held by the plugin and one ref held by us
+ // (outlives the plugin), and delete the instance.
+ resource_tracker().DidCreateInstance(instance);
+ scoped_refptr<MyMockResource> resource = new MyMockResource(instance);
+ resource->GetReference();
+ EXPECT_EQ(1, mock_resource_alive_count);
+ resource_tracker().DidDeleteInstance(instance);
+
+ // The resource should NOT have been deleted, and it should have received both
+ // a "last plugin ref was deleted" and a "instance was deleted" notification.
+ EXPECT_EQ(1, mock_resource_alive_count);
+ EXPECT_EQ(1, last_plugin_ref_was_deleted_count);
+ EXPECT_EQ(1, instance_was_deleted_count);
+ EXPECT_EQ(0, resource->pp_instance());
+
+ resource = NULL;
+ EXPECT_EQ(0, mock_resource_alive_count);
+}
+
+} // namespace ppapi
diff --git a/ppapi/shared_impl/tracker_base.h b/ppapi/shared_impl/tracker_base.h
index 4b45a79..63585ea 100644
--- a/ppapi/shared_impl/tracker_base.h
+++ b/ppapi/shared_impl/tracker_base.h
@@ -14,7 +14,7 @@
namespace ppapi {
class FunctionGroupBase;
-class ResourceObjectBase;
+class ResourceTracker;
class VarTracker;
// Tracks resource and function APIs, providing a mapping between ID and
@@ -37,20 +37,13 @@ class TrackerBase {
// Init() first (it should be unnecessary to NULL-check this).
static TrackerBase* Get();
- // Returns the resource object corresponding to the given ID, or NULL if
- // there isn't one.
- virtual ResourceObjectBase* GetResourceAPI(PP_Resource res) = 0;
-
// Returns the function object corresponding to the given ID, or NULL if
// there isn't one.
virtual FunctionGroupBase* GetFunctionAPI(PP_Instance inst,
pp::proxy::InterfaceID id) = 0;
- // Returns the instance corresponding to the given resource, or 0 if the
- // resource is invalid.
- virtual PP_Instance GetInstanceForResource(PP_Resource resource) = 0;
-
virtual VarTracker* GetVarTracker() = 0;
+ virtual ResourceTracker* GetResourceTracker() = 0;
};
} // namespace ppapi
diff --git a/ppapi/shared_impl/video_decoder_impl.cc b/ppapi/shared_impl/video_decoder_impl.cc
index ef20f8b..ecdde86 100644
--- a/ppapi/shared_impl/video_decoder_impl.cc
+++ b/ppapi/shared_impl/video_decoder_impl.cc
@@ -8,6 +8,7 @@
#include "gpu/command_buffer/client/gles2_implementation.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/proxy/plugin_resource_tracker.h"
+#include "ppapi/shared_impl/resource_tracker.h"
#include "ppapi/thunk/ppb_context_3d_api.h"
#include "ppapi/thunk/enter.h"
@@ -33,7 +34,7 @@ bool VideoDecoderImpl::Init(PP_Resource context3d_id,
DCHECK(!gles2_impl_ && !context3d_id_);
gles2_impl_ = context3d->GetGLES2Impl();
- AddRefResource(context3d_id);
+ TrackerBase::Get()->GetResourceTracker()->AddRefResource(context3d_id);
context3d_id_ = context3d_id;
return true;
}
@@ -41,7 +42,7 @@ bool VideoDecoderImpl::Init(PP_Resource context3d_id,
void VideoDecoderImpl::Destroy() {
context3d_id_ = 0;
gles2_impl_ = NULL;
- UnrefResource(context3d_id_);
+ TrackerBase::Get()->GetResourceTracker()->ReleaseResource(context3d_id_);
}
bool VideoDecoderImpl::SetFlushCallback(PP_CompletionCallback callback) {
diff --git a/ppapi/shared_impl/video_decoder_impl.h b/ppapi/shared_impl/video_decoder_impl.h
index 6cd8044..191efa9 100644
--- a/ppapi/shared_impl/video_decoder_impl.h
+++ b/ppapi/shared_impl/video_decoder_impl.h
@@ -11,7 +11,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "ppapi/c/dev/ppb_video_decoder_dev.h"
-#include "ppapi/shared_impl/resource_object_base.h"
+#include "ppapi/shared_impl/resource.h"
#include "ppapi/thunk/ppb_video_decoder_api.h"
namespace gpu {
@@ -61,11 +61,6 @@ class VideoDecoderImpl : public thunk::PPB_VideoDecoder_API {
thunk::PPB_Context3D_API* context,
const PP_VideoConfigElement* dec_config);
- // TODO(fischman/vrk): Remove accordingly when brettw has merged resource
- // trackers.
- virtual void AddRefResource(PP_Resource resource) = 0;
- virtual void UnrefResource(PP_Resource resource) = 0;
-
private:
// Key: bitstream_buffer_id, value: callback to run when bitstream decode is
// done.