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