OLD | NEW |
---|---|
(Empty) | |
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_priv.h" | |
9 #include "SkRefCnt.h" | |
10 #include "SkDiscardableMemory.h" | |
11 | |
12 SkCachedData::SkCachedData(void* data, size_t size) | |
13 : fData(data) | |
14 , fSize(size) | |
15 , fRefCnt(1) | |
16 , fStorageType(kMalloc_StorageType) | |
17 , fInCache(false) | |
18 , fIsLocked(true) | |
19 { | |
20 fStorage.fMalloc = data; | |
21 } | |
22 | |
23 SkCachedData::SkCachedData(size_t size, SkDiscardableMemory* dm) | |
24 : fData(dm->data()) | |
25 , fSize(size) | |
26 , fRefCnt(1) | |
27 , fStorageType(kDiscardableMemory_StorageType) | |
28 , fInCache(false) | |
29 , fIsLocked(true) | |
30 { | |
31 fStorage.fDM = dm; | |
32 } | |
33 | |
34 SkCachedData::~SkCachedData() { | |
35 switch (fStorageType) { | |
36 case kMalloc_StorageType: | |
37 sk_free(fStorage.fMalloc); | |
38 break; | |
39 case kDiscardableMemory_StorageType: | |
40 SkDELETE(fStorage.fDM); | |
41 break; | |
42 } | |
43 } | |
44 | |
45 class SkCachedData::AutoMutexWritable { | |
46 public: | |
47 AutoMutexWritable(const SkCachedData* cd) : fCD(const_cast<SkCachedData*>(cd )) { | |
48 fCD->get_mutex().acquire(); | |
49 fCD->validate(); | |
50 } | |
51 ~AutoMutexWritable() { | |
52 fCD->validate(); | |
53 fCD->get_mutex().release(); | |
54 } | |
55 | |
56 SkCachedData* get() { return fCD; } | |
57 SkCachedData* operator->() { return fCD; } | |
58 | |
59 private: | |
60 SkCachedData* fCD; | |
61 }; | |
62 | |
63 void SkCachedData::internalRef(bool fromCache) const { | |
64 AutoMutexWritable writable(this); | |
mtklein
2014/09/27 14:47:49
I really like this pattern.
| |
65 | |
66 SkASSERT(!fromCache || !writable->fInCache); // we can only be in a cache once | |
67 | |
68 if ((1 == writable->fRefCnt) && fInCache) { | |
69 writable->in_mutex_lock(); | |
70 } | |
71 | |
72 writable->fRefCnt += 1; | |
73 writable->fInCache |= fromCache; | |
mtklein
2014/09/27 14:47:49
Just a nit, but I'd go with ||= here. It really i
reed1
2014/09/27 17:25:58
||= isn't legal afaik
However, I did rewrite to u
| |
74 } | |
75 | |
76 bool SkCachedData::doInternalUnref(bool fromCache) const { | |
77 AutoMutexWritable writable(this); | |
78 | |
79 switch (writable->fRefCnt) { | |
mtklein
2014/09/27 14:47:49
These guys might read better if you decrement firs
reed1
2014/09/27 17:25:58
Done.
| |
80 case 1: | |
81 // we're going to be deleted, so we need to be unlocked (for Discard ableMemory) | |
82 if (writable->fIsLocked) { | |
83 writable->in_mutex_unlock(); | |
84 } | |
85 break; | |
86 case 2: | |
87 if (fInCache && !fromCache) { | |
88 // If we're down to 1 owner, and that owner is the cache, this i t is safe | |
89 // to unlock (and mutate fData) even if the cache is in a differ ent thread, | |
90 // as the cache is NOT allowed to inspect or use fData. | |
91 writable->in_mutex_unlock(); | |
92 } | |
93 break; | |
94 default: | |
95 break; | |
96 } | |
97 | |
98 if (fromCache) { | |
99 SkASSERT(writable->fInCache); | |
100 writable->fInCache = false; | |
101 } | |
102 | |
103 // return true when we need to be deleted | |
104 return 0 == --writable->fRefCnt; | |
105 } | |
106 | |
107 void SkCachedData::internalUnref(bool fromCache) const { | |
108 if (this->doInternalUnref(fromCache)) { | |
109 // can't delete inside doInternalUnref, since it is locking a mutex (whi ch we own) | |
110 SkDELETE(this); | |
111 } | |
112 } | |
113 | |
114 void SkCachedData::in_mutex_lock() { | |
115 this->assert_in_mutex(); | |
116 | |
117 SkASSERT(!fIsLocked); | |
118 fIsLocked = true; | |
119 | |
120 switch (fStorageType) { | |
121 case kMalloc_StorageType: | |
122 this->setData(fStorage.fMalloc); | |
123 break; | |
124 case kDiscardableMemory_StorageType: | |
125 if (fStorage.fDM->lock()) { | |
126 this->setData(fStorage.fDM->data()); | |
127 } else { | |
128 this->setData(NULL); // signal failure to lock, contents are g one | |
129 } | |
130 break; | |
131 } | |
132 } | |
133 | |
134 void SkCachedData::in_mutex_unlock() { | |
135 this->assert_in_mutex(); | |
136 | |
137 SkASSERT(fIsLocked); | |
138 fIsLocked = false; | |
139 | |
140 switch (fStorageType) { | |
141 case kMalloc_StorageType: | |
142 // nothing to do/check | |
143 break; | |
144 case kDiscardableMemory_StorageType: | |
145 if (fData) { // did the previous lock succeed? | |
146 fStorage.fDM->unlock(); | |
147 } | |
148 break; | |
149 } | |
150 this->setData(NULL); // signal that we're in an unlocked state | |
151 } | |
152 | |
153 #ifdef SK_DEBUG | |
154 void SkCachedData::validate() const { | |
155 if (fIsLocked) { | |
156 SkASSERT((fInCache && fRefCnt > 1) || !fInCache); | |
157 switch (fStorageType) { | |
158 case kMalloc_StorageType: | |
159 SkASSERT(fData == fStorage.fMalloc); | |
160 break; | |
161 case kDiscardableMemory_StorageType: | |
162 // fData can be null or the actual value, depending if DM's lock succeeded | |
163 break; | |
164 } | |
165 } else { | |
166 SkASSERT((fInCache && 1 == fRefCnt) || (0 == fRefCnt)); | |
167 SkASSERT(NULL == fData); | |
168 } | |
169 } | |
170 #endif | |
OLD | NEW |