Index: ppapi/host/ppapi_host.cc |
diff --git a/ppapi/host/ppapi_host.cc b/ppapi/host/ppapi_host.cc |
index 130bc875569dcd61fe1d318ea682f5db927431a6..f24eb01935f2cadede3a56f29a85c5e07c3000cf 100644 |
--- a/ppapi/host/ppapi_host.cc |
+++ b/ppapi/host/ppapi_host.cc |
@@ -44,6 +44,9 @@ PpapiHost::~PpapiHost() { |
// The resources may also want to use us in their destructors. |
resources_.clear(); |
pending_resource_hosts_.clear(); |
+ // At this point, all hosts should have Unpinned anything they depend on in |
+ // their destructors, so this map should be empty. |
+ DCHECK(owner_to_owned_map_.empty()) << "A ResourceHost forgot to Unpin"; |
} |
bool PpapiHost::Send(IPC::Message* msg) { |
@@ -164,6 +167,35 @@ void PpapiHost::AddInstanceMessageFilter( |
instance_message_filters_.push_back(filter.release()); |
} |
+ResourceHost* PpapiHost::GetResourceHost(PP_Resource resource) const { |
+ ResourceMap::const_iterator found = resources_.find(resource); |
+ return found == resources_.end() ? NULL : found->second.get(); |
+} |
+ |
+void PpapiHost::PinHost(ResourceHost* owner_host, ResourceHost* owned_host) { |
+ // Only allow a ResourceHost to be "owned" or be an "owner", but not both. |
+ // This prevents graphs that are >1 level deep and also prevents cycles. |
+ DCHECK(owner_to_owned_map_.count(owned_host) == 0) |
+ << "A ResourceHost is not allowed to own and also be owned."; |
+ linked_ptr<ResourceHost> owned_linked_ptr = RawToLinkedPtr(owned_host); |
+ DCHECK(owned_linked_ptr.get()); |
+ DCHECK(owner_to_owned_map_[owner_host].count(owned_linked_ptr) == 0); |
+ owner_to_owned_map_[owner_host][owned_linked_ptr]++; |
+} |
+ |
+void PpapiHost::UnpinHost(ResourceHost* owner_host, ResourceHost* owned_host) { |
+ OwnerToOwnedHostMap::iterator iter = owner_to_owned_map_.find(owner_host); |
+ DCHECK(iter != owner_to_owned_map_.end()); |
+ if (iter != owner_to_owned_map_.end()) { |
+ linked_ptr<ResourceHost> owned_linked_ptr = RawToLinkedPtr(owned_host); |
+ PinCountMap::iterator count_iter = iter->second.find(owned_linked_ptr); |
+ if (--count_iter->second == 0) |
+ iter->second.erase(count_iter); |
+ if (iter->second.empty()) |
+ owner_to_owned_map_.erase(iter); |
+ } |
+} |
+ |
void PpapiHost::OnHostMsgResourceCall( |
const proxy::ResourceMessageCallParams& params, |
const IPC::Message& nested_msg) { |
@@ -276,9 +308,22 @@ void PpapiHost::OnHostMsgResourceDestroyed(PP_Resource resource) { |
resources_.erase(found); |
} |
-ResourceHost* PpapiHost::GetResourceHost(PP_Resource resource) const { |
- ResourceMap::const_iterator found = resources_.find(resource); |
- return found == resources_.end() ? NULL : found->second.get(); |
+linked_ptr<ResourceHost> PpapiHost::RawToLinkedPtr(ResourceHost* host) { |
+ if (host->pp_resource()) { |
+ // If it has a valid PP_Resource, it's not "pending" and therefore should |
+ // be in resources_. |
+ DCHECK(resources_.count(host->pp_resource())); |
+ return resources_[host->pp_resource()]; |
+ } else { |
+ // It's a pending host. This map should be small, so a linear search is OK. |
+ PendingHostResourceMap::iterator iter = pending_resource_hosts_.begin(); |
+ for (; iter != pending_resource_hosts_.end(); ++iter) { |
+ if (host == iter->second.get()) |
+ return iter->second; |
+ } |
+ } |
+ NOTREACHED(); |
+ return linked_ptr<ResourceHost>(); |
} |
} // namespace host |