1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "fake_ppapi/fake_resource_manager.h" 6 #include "gtest/gtest.h" 7 #include "sdk_util/auto_lock.h" 8 9 FakeResourceManager::FakeResourceManager() : next_handle_(1) {} 10 11 FakeResourceManager::~FakeResourceManager() { 12 // The ref counts for all resources should be zero. 13 for (ResourceMap::iterator iter = resource_map_.begin(); 14 iter != resource_map_.end(); 15 ++iter) { 16 const FakeResourceTracker* resource_tracker = iter->second; 17 EXPECT_EQ(0, resource_tracker->ref_count()) << "Leaked resource " 18 << resource_tracker->classname() 19 << "(" << iter->first 20 << "), created at " 21 << resource_tracker->file() 22 << ":" 23 << resource_tracker->line(); 24 delete resource_tracker; 25 } 26 } 27 28 PP_Resource FakeResourceManager::Create(FakeResource* resource, 29 const char* classname, 30 const char* file, 31 int line) { 32 AUTO_LOCK(lock_); 33 PP_Resource handle = next_handle_++; 34 FakeResourceTracker* resource_tracker = 35 new FakeResourceTracker(resource, classname, file, line); 36 std::pair<ResourceMap::iterator, bool> result = 37 resource_map_.insert(ResourceMap::value_type(handle, resource_tracker)); 38 EXPECT_TRUE(result.second); 39 result.first->second->AddRef(); 40 return handle; 41 } 42 43 void FakeResourceManager::AddRef(PP_Resource handle) { 44 AUTO_LOCK(lock_); 45 ResourceMap::iterator iter = resource_map_.find(handle); 46 ASSERT_NE(resource_map_.end(), iter) << "AddRefing unknown resource " 47 << handle; 48 49 FakeResourceTracker* resource_tracker = iter->second; 50 EXPECT_LT(0, resource_tracker->ref_count()) << "AddRefing freed resource " 51 << resource_tracker->classname() 52 << "(" << handle 53 << "), created at " 54 << resource_tracker->file() << ":" 55 << resource_tracker->line(); 56 resource_tracker->AddRef(); 57 } 58 59 void FakeResourceManager::Release(PP_Resource handle) { 60 if (handle == 0) 61 return; 62 63 sdk_util::AutoLock lock(lock_); 64 ResourceMap::iterator iter = resource_map_.find(handle); 65 ASSERT_NE(resource_map_.end(), iter) << "Releasing unknown resource " 66 << handle; 67 68 FakeResourceTracker* resource_tracker = iter->second; 69 EXPECT_LT(0, resource_tracker->ref_count()) << "Releasing freed resource " 70 << resource_tracker->classname() 71 << "(" << handle 72 << "), created at " 73 << resource_tracker->file() << ":" 74 << resource_tracker->line(); 75 resource_tracker->Release(); 76 // It's OK to access the tracker when its refcount is zero; it doesn't 77 // actually destroy the object until the manager is destroyed. 78 if (resource_tracker->ref_count() == 0) { 79 // Remove the resource from this tracker. 80 FakeResource* resource = resource_tracker->Pass(); 81 // Release the lock before we call Destroy; resources can call 82 // FakeResourceManager::Release(), which will deadlock if we are already 83 // holding the lock. 84 lock.Unlock(); 85 86 resource->Destroy(); 87 delete resource; 88 } 89 } 90 91 FakeResourceTracker* FakeResourceManager::Get(PP_Resource handle, 92 bool not_found_ok) { 93 AUTO_LOCK(lock_); 94 ResourceMap::iterator iter = resource_map_.find(handle); 95 if (iter == resource_map_.end()) { 96 if (!not_found_ok) { 97 // Can't use FAIL() because it tries to return void. 98 EXPECT_TRUE(false) << "Trying to get resource " << handle 99 << " that doesn't exist!"; 100 } 101 102 return NULL; 103 } 104 105 FakeResourceTracker* resource_tracker = iter->second; 106 EXPECT_LT(0, resource_tracker->ref_count()) << "Accessing freed resource " 107 << resource_tracker->classname() 108 << "(" << handle 109 << "), created at " 110 << resource_tracker->file() << ":" 111 << resource_tracker->line(); 112 113 return iter->second; 114 } 115 116 FakeResourceTracker::FakeResourceTracker(FakeResource* resource, 117 const char* classname, 118 const char* file, 119 int line) 120 : resource_(resource), 121 classname_(classname), 122 file_(file), 123 line_(line), 124 ref_count_(0) {} 125 126 FakeResourceTracker::~FakeResourceTracker() { delete resource_; } 127 128 bool FakeResourceTracker::CheckType(const char* other_classname) const { 129 if (strcmp(other_classname, classname_) != 0) { 130 // Repeat the expectation, just to print out a nice error message before we 131 // crash. :) 132 EXPECT_STREQ(classname_, other_classname); 133 return false; 134 } 135 136 return true; 137 } 138