This source file includes following definitions.
- weak_ptr_factory_
- CheckThreadingPreconditions
- GetResource
- AddRefResource
- ReleaseResource
- ReleaseResourceSoon
- DidCreateInstance
- DidDeleteInstance
- GetLiveObjectsForInstance
- UseOddResourceValueInDebugMode
- AddResource
- RemoveResource
- LastPluginRefWasDeleted
- GetNextResourceValue
- CanOperateOnResource
#include "ppapi/shared_impl/resource_tracker.h"
#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/message_loop/message_loop.h"
#include "ppapi/shared_impl/callback_tracker.h"
#include "ppapi/shared_impl/id_assignment.h"
#include "ppapi/shared_impl/ppapi_globals.h"
#include "ppapi/shared_impl/proxy_lock.h"
#include "ppapi/shared_impl/resource.h"
namespace ppapi {
ResourceTracker::ResourceTracker(ThreadMode thread_mode)
: last_resource_value_(0), weak_ptr_factory_(this) {
if (thread_mode == SINGLE_THREADED)
thread_checker_.reset(new base::ThreadChecker);
}
ResourceTracker::~ResourceTracker() {}
void ResourceTracker::CheckThreadingPreconditions() const {
DCHECK(!thread_checker_ || thread_checker_->CalledOnValidThread());
#ifndef NDEBUG
ProxyLock::AssertAcquired();
#endif
}
Resource* ResourceTracker::GetResource(PP_Resource res) const {
CheckThreadingPreconditions();
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) {
CheckThreadingPreconditions();
DLOG_IF(ERROR, !CheckIdType(res, PP_ID_TYPE_RESOURCE))
<< res << " is not a PP_Resource.";
DCHECK(CanOperateOnResource(res));
ResourceMap::iterator i = live_resources_.find(res);
if (i == live_resources_.end())
return;
if (i->second.second ==
std::numeric_limits<ResourceAndRefCount::second_type>::max())
return;
if (i->second.second == 0)
i->second.first->AddRef();
i->second.second++;
return;
}
void ResourceTracker::ReleaseResource(PP_Resource res) {
CheckThreadingPreconditions();
DLOG_IF(ERROR, !CheckIdType(res, PP_ID_TYPE_RESOURCE))
<< res << " is not a PP_Resource.";
DCHECK(CanOperateOnResource(res));
ResourceMap::iterator i = live_resources_.find(res);
if (i == live_resources_.end())
return;
if (i->second.second == 0)
return;
i->second.second--;
if (i->second.second == 0) {
LastPluginRefWasDeleted(i->second.first);
i->second.first->Release();
}
}
void ResourceTracker::ReleaseResourceSoon(PP_Resource res) {
base::MessageLoop::current()->PostNonNestableTask(
FROM_HERE,
RunWhileLocked(base::Bind(&ResourceTracker::ReleaseResource,
weak_ptr_factory_.GetWeakPtr(),
res)));
}
void ResourceTracker::DidCreateInstance(PP_Instance instance) {
CheckThreadingPreconditions();
if (instance_map_.find(instance) != instance_map_.end())
return;
instance_map_[instance] = linked_ptr<InstanceData>(new InstanceData);
}
void ResourceTracker::DidDeleteInstance(PP_Instance instance) {
CheckThreadingPreconditions();
InstanceMap::iterator found_instance = instance_map_.find(instance);
if (found_instance == instance_map_.end())
return;
InstanceData& data = *found_instance->second;
ResourceSet to_delete = data.resources;
ResourceSet::iterator cur = to_delete.begin();
while (cur != to_delete.end()) {
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) {
LastPluginRefWasDeleted(resource);
found_resource->second.second = 0;
resource->Release();
}
}
cur++;
}
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->NotifyInstanceWasDeleted();
cur++;
}
instance_map_.erase(instance);
}
int ResourceTracker::GetLiveObjectsForInstance(PP_Instance instance) const {
CheckThreadingPreconditions();
InstanceMap::const_iterator found = instance_map_.find(instance);
if (found == instance_map_.end())
return 0;
return static_cast<int>(found->second->resources.size());
}
void ResourceTracker::UseOddResourceValueInDebugMode() {
#if !defined(NDEBUG)
DCHECK_EQ(0, last_resource_value_);
++last_resource_value_;
#endif
}
PP_Resource ResourceTracker::AddResource(Resource* object) {
CheckThreadingPreconditions();
if (last_resource_value_ >= kMaxPPId)
return 0;
PP_Resource new_id = MakeTypedId(GetNextResourceValue(), PP_ID_TYPE_RESOURCE);
if (object->pp_instance()) {
InstanceMap::iterator found = instance_map_.find(object->pp_instance());
if (found == instance_map_.end()) {
VLOG(1) << "Failed to find plugin instance in instance map";
return 0;
}
found->second->resources.insert(new_id);
}
live_resources_[new_id] = ResourceAndRefCount(object, 0);
return new_id;
}
void ResourceTracker::RemoveResource(Resource* object) {
CheckThreadingPreconditions();
PP_Resource pp_resource = object->pp_resource();
InstanceMap::iterator found = instance_map_.find(object->pp_instance());
if (found != instance_map_.end())
found->second->resources.erase(pp_resource);
live_resources_.erase(pp_resource);
}
void ResourceTracker::LastPluginRefWasDeleted(Resource* object) {
const bool is_message_loop = (object->AsPPB_MessageLoop_API() != NULL);
CHECK(object->pp_instance() || is_message_loop);
CallbackTracker* callback_tracker =
PpapiGlobals::Get()->GetCallbackTrackerForInstance(object->pp_instance());
CHECK(callback_tracker || is_message_loop);
if (callback_tracker)
callback_tracker->PostAbortForResource(object->pp_resource());
object->NotifyLastPluginRefWasDeleted();
}
int32 ResourceTracker::GetNextResourceValue() {
#if defined(NDEBUG)
return ++last_resource_value_;
#else
last_resource_value_ += 2;
return last_resource_value_;
#endif
}
bool ResourceTracker::CanOperateOnResource(PP_Resource res) {
#if defined(NDEBUG)
return true;
#else
if (res == 0)
return true;
return ((res >> kPPIdTypeBits) & 1) == (last_resource_value_ & 1);
#endif
}
}