blob: 0f3ca649aa0cca17c4b4ca273d86dde3033c5670 [file] [log] [blame]
reed9d93c2e2014-10-08 05:17:12 -07001/*
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"
reed9d93c2e2014-10-08 05:17:12 -07009#include "SkDiscardableMemory.h"
Herb Derbyb549cc32017-03-27 13:35:15 -040010#include "SkMalloc.h"
reed9d93c2e2014-10-08 05:17:12 -070011
12//#define TRACK_CACHEDDATA_LIFETIME
13
14#ifdef TRACK_CACHEDDATA_LIFETIME
15static int32_t gCachedDataCounter;
16
17static void inc() {
18 int32_t oldCount = sk_atomic_inc(&gCachedDataCounter);
19 SkDebugf("SkCachedData inc %d\n", oldCount + 1);
20}
21
22static void dec() {
23 int32_t oldCount = sk_atomic_dec(&gCachedDataCounter);
24 SkDebugf("SkCachedData dec %d\n", oldCount - 1);
25}
26#else
27static void inc() {}
28static void dec() {}
29#endif
30
31SkCachedData::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
43SkCachedData::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
55SkCachedData::~SkCachedData() {
56 switch (fStorageType) {
57 case kMalloc_StorageType:
58 sk_free(fStorage.fMalloc);
59 break;
60 case kDiscardableMemory_StorageType:
halcanary385fe4d2015-08-26 13:07:48 -070061 delete fStorage.fDM;
reed9d93c2e2014-10-08 05:17:12 -070062 break;
63 }
64 dec();
65}
66
67class SkCachedData::AutoMutexWritable {
68public:
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
81private:
82 SkCachedData* fCD;
83};
84
85void SkCachedData::internalRef(bool fromCache) const {
86 AutoMutexWritable(this)->inMutexRef(fromCache);
87}
88
89void 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)
halcanary385fe4d2015-08-26 13:07:48 -070092 delete this;
reed9d93c2e2014-10-08 05:17:12 -070093 }
94}
95
96///////////////////////////////////////////////////////////////////////////////////////////////////
97
98void SkCachedData::inMutexRef(bool fromCache) {
99 if ((1 == fRefCnt) && fInCache) {
100 this->inMutexLock();
101 }
halcanary9d524f22016-03-29 09:03:52 -0700102
reed9d93c2e2014-10-08 05:17:12 -0700103 fRefCnt += 1;
104 if (fromCache) {
105 SkASSERT(!fInCache);
106 fInCache = true;
107 }
108}
109
110bool 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 }
halcanary9d524f22016-03-29 09:03:52 -0700129
reed9d93c2e2014-10-08 05:17:12 -0700130 if (fromCache) {
131 SkASSERT(fInCache);
132 fInCache = false;
133 }
halcanary9d524f22016-03-29 09:03:52 -0700134
reed9d93c2e2014-10-08 05:17:12 -0700135 // return true when we need to be deleted
136 return 0 == fRefCnt;
137}
138
139void SkCachedData::inMutexLock() {
140 fMutex.assertHeld();
halcanary9d524f22016-03-29 09:03:52 -0700141
reed9d93c2e2014-10-08 05:17:12 -0700142 SkASSERT(!fIsLocked);
143 fIsLocked = true;
halcanary9d524f22016-03-29 09:03:52 -0700144
reed9d93c2e2014-10-08 05:17:12 -0700145 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 {
halcanary96fcdcc2015-08-27 07:41:13 -0700155 this->setData(nullptr); // signal failure to lock, contents are gone
reed9d93c2e2014-10-08 05:17:12 -0700156 }
157 break;
158 }
159}
160
161void SkCachedData::inMutexUnlock() {
162 fMutex.assertHeld();
halcanary9d524f22016-03-29 09:03:52 -0700163
reed9d93c2e2014-10-08 05:17:12 -0700164 SkASSERT(fIsLocked);
165 fIsLocked = false;
halcanary9d524f22016-03-29 09:03:52 -0700166
reed9d93c2e2014-10-08 05:17:12 -0700167 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 }
halcanary96fcdcc2015-08-27 07:41:13 -0700177 this->setData(nullptr); // signal that we're in an unlocked state
reed9d93c2e2014-10-08 05:17:12 -0700178}
179
180///////////////////////////////////////////////////////////////////////////////////////////////////
181
182#ifdef SK_DEBUG
183void 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));
halcanary96fcdcc2015-08-27 07:41:13 -0700196 SkASSERT(nullptr == fData);
reed9d93c2e2014-10-08 05:17:12 -0700197 }
198}
199#endif