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