1 /* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkCachedData.h" 9 #include "SkDiscardableMemory.h" 10 #include "SkMalloc.h" 11 12 //#define TRACK_CACHEDDATA_LIFETIME 13 14 #ifdef TRACK_CACHEDDATA_LIFETIME 15 static int32_t gCachedDataCounter; 16 17 static void inc() { 18 int32_t oldCount = sk_atomic_inc(&gCachedDataCounter); 19 SkDebugf("SkCachedData inc %d\n", oldCount + 1); 20 } 21 22 static void dec() { 23 int32_t oldCount = sk_atomic_dec(&gCachedDataCounter); 24 SkDebugf("SkCachedData dec %d\n", oldCount - 1); 25 } 26 #else 27 static void inc() {} 28 static void dec() {} 29 #endif 30 31 SkCachedData::SkCachedData(void* data, size_t size) 32 : fData(data) 33 , fSize(size) 34 , fRefCnt(1) 35 , fStorageType(kMalloc_StorageType) 36 , fInCache(false) 37 , fIsLocked(true) 38 { 39 fStorage.fMalloc = data; 40 inc(); 41 } 42 43 SkCachedData::SkCachedData(size_t size, SkDiscardableMemory* dm) 44 : fData(dm->data()) 45 , fSize(size) 46 , fRefCnt(1) 47 , fStorageType(kDiscardableMemory_StorageType) 48 , fInCache(false) 49 , fIsLocked(true) 50 { 51 fStorage.fDM = dm; 52 inc(); 53 } 54 55 SkCachedData::~SkCachedData() { 56 switch (fStorageType) { 57 case kMalloc_StorageType: 58 sk_free(fStorage.fMalloc); 59 break; 60 case kDiscardableMemory_StorageType: 61 delete fStorage.fDM; 62 break; 63 } 64 dec(); 65 } 66 67 class SkCachedData::AutoMutexWritable { 68 public: 69 AutoMutexWritable(const SkCachedData* cd) : fCD(const_cast<SkCachedData*>(cd)) { 70 fCD->fMutex.acquire(); 71 fCD->validate(); 72 } 73 ~AutoMutexWritable() { 74 fCD->validate(); 75 fCD->fMutex.release(); 76 } 77 78 SkCachedData* get() { return fCD; } 79 SkCachedData* operator->() { return fCD; } 80 81 private: 82 SkCachedData* fCD; 83 }; 84 85 void SkCachedData::internalRef(bool fromCache) const { 86 AutoMutexWritable(this)->inMutexRef(fromCache); 87 } 88 89 void SkCachedData::internalUnref(bool fromCache) const { 90 if (AutoMutexWritable(this)->inMutexUnref(fromCache)) { 91 // can't delete inside doInternalUnref, since it is locking a mutex (which we own) 92 delete this; 93 } 94 } 95 96 /////////////////////////////////////////////////////////////////////////////////////////////////// 97 98 void SkCachedData::inMutexRef(bool fromCache) { 99 if ((1 == fRefCnt) && fInCache) { 100 this->inMutexLock(); 101 } 102 103 fRefCnt += 1; 104 if (fromCache) { 105 SkASSERT(!fInCache); 106 fInCache = true; 107 } 108 } 109 110 bool SkCachedData::inMutexUnref(bool fromCache) { 111 switch (--fRefCnt) { 112 case 0: 113 // we're going to be deleted, so we need to be unlocked (for DiscardableMemory) 114 if (fIsLocked) { 115 this->inMutexUnlock(); 116 } 117 break; 118 case 1: 119 if (fInCache && !fromCache) { 120 // If we're down to 1 owner, and that owner is the cache, this it is safe 121 // to unlock (and mutate fData) even if the cache is in a different thread, 122 // as the cache is NOT allowed to inspect or use fData. 123 this->inMutexUnlock(); 124 } 125 break; 126 default: 127 break; 128 } 129 130 if (fromCache) { 131 SkASSERT(fInCache); 132 fInCache = false; 133 } 134 135 // return true when we need to be deleted 136 return 0 == fRefCnt; 137 } 138 139 void SkCachedData::inMutexLock() { 140 fMutex.assertHeld(); 141 142 SkASSERT(!fIsLocked); 143 fIsLocked = true; 144 145 switch (fStorageType) { 146 case kMalloc_StorageType: 147 this->setData(fStorage.fMalloc); 148 break; 149 case kDiscardableMemory_StorageType: 150 if (fStorage.fDM->lock()) { 151 void* ptr = fStorage.fDM->data(); 152 SkASSERT(ptr); 153 this->setData(ptr); 154 } else { 155 this->setData(nullptr); // signal failure to lock, contents are gone 156 } 157 break; 158 } 159 } 160 161 void SkCachedData::inMutexUnlock() { 162 fMutex.assertHeld(); 163 164 SkASSERT(fIsLocked); 165 fIsLocked = false; 166 167 switch (fStorageType) { 168 case kMalloc_StorageType: 169 // nothing to do/check 170 break; 171 case kDiscardableMemory_StorageType: 172 if (fData) { // did the previous lock succeed? 173 fStorage.fDM->unlock(); 174 } 175 break; 176 } 177 this->setData(nullptr); // signal that we're in an unlocked state 178 } 179 180 /////////////////////////////////////////////////////////////////////////////////////////////////// 181 182 #ifdef SK_DEBUG 183 void SkCachedData::validate() const { 184 if (fIsLocked) { 185 SkASSERT((fInCache && fRefCnt > 1) || !fInCache); 186 switch (fStorageType) { 187 case kMalloc_StorageType: 188 SkASSERT(fData == fStorage.fMalloc); 189 break; 190 case kDiscardableMemory_StorageType: 191 // fData can be null or the actual value, depending if DM's lock succeeded 192 break; 193 } 194 } else { 195 SkASSERT((fInCache && 1 == fRefCnt) || (0 == fRefCnt)); 196 SkASSERT(nullptr == fData); 197 } 198 } 199 #endif 200