2 * Copyright 2014 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "SkCachedData.h"
10 #include "SkDiscardableMemory.h"
12 //#define TRACK_CACHEDDATA_LIFETIME
14 #ifdef TRACK_CACHEDDATA_LIFETIME
15 static int32_t gCachedDataCounter;
18 int32_t oldCount = sk_atomic_inc(&gCachedDataCounter);
19 SkDebugf("SkCachedData inc %d\n", oldCount + 1);
23 int32_t oldCount = sk_atomic_dec(&gCachedDataCounter);
24 SkDebugf("SkCachedData dec %d\n", oldCount - 1);
31 SkCachedData::SkCachedData(void* data, size_t size)
35 , fStorageType(kMalloc_StorageType)
39 fStorage.fMalloc = data;
43 SkCachedData::SkCachedData(size_t size, SkDiscardableMemory* dm)
47 , fStorageType(kDiscardableMemory_StorageType)
55 SkCachedData::~SkCachedData() {
56 switch (fStorageType) {
57 case kMalloc_StorageType:
58 sk_free(fStorage.fMalloc);
60 case kDiscardableMemory_StorageType:
61 SkDELETE(fStorage.fDM);
67 class SkCachedData::AutoMutexWritable {
69 AutoMutexWritable(const SkCachedData* cd) : fCD(const_cast<SkCachedData*>(cd)) {
70 fCD->fMutex.acquire();
73 ~AutoMutexWritable() {
75 fCD->fMutex.release();
78 SkCachedData* get() { return fCD; }
79 SkCachedData* operator->() { return fCD; }
85 void SkCachedData::internalRef(bool fromCache) const {
86 AutoMutexWritable(this)->inMutexRef(fromCache);
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)
96 ///////////////////////////////////////////////////////////////////////////////////////////////////
98 void SkCachedData::inMutexRef(bool fromCache) {
99 if ((1 == fRefCnt) && fInCache) {
110 bool SkCachedData::inMutexUnref(bool fromCache) {
113 // we're going to be deleted, so we need to be unlocked (for DiscardableMemory)
115 this->inMutexUnlock();
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();
135 // return true when we need to be deleted
139 void SkCachedData::inMutexLock() {
142 SkASSERT(!fIsLocked);
145 switch (fStorageType) {
146 case kMalloc_StorageType:
147 this->setData(fStorage.fMalloc);
149 case kDiscardableMemory_StorageType:
150 if (fStorage.fDM->lock()) {
151 void* ptr = fStorage.fDM->data();
155 this->setData(NULL); // signal failure to lock, contents are gone
161 void SkCachedData::inMutexUnlock() {
167 switch (fStorageType) {
168 case kMalloc_StorageType:
169 // nothing to do/check
171 case kDiscardableMemory_StorageType:
172 if (fData) { // did the previous lock succeed?
173 fStorage.fDM->unlock();
177 this->setData(NULL); // signal that we're in an unlocked state
180 ///////////////////////////////////////////////////////////////////////////////////////////////////
183 void SkCachedData::validate() const {
185 SkASSERT((fInCache && fRefCnt > 1) || !fInCache);
186 switch (fStorageType) {
187 case kMalloc_StorageType:
188 SkASSERT(fData == fStorage.fMalloc);
190 case kDiscardableMemory_StorageType:
191 // fData can be null or the actual value, depending if DM's lock succeeded
195 SkASSERT((fInCache && 1 == fRefCnt) || (0 == fRefCnt));
196 SkASSERT(NULL == fData);