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 #ifndef SkCachedData_DEFINED 9 #define SkCachedData_DEFINED 10 11 #include "SkMutex.h" 12 #include "SkTypes.h" 13 14 class SkDiscardableMemory; 15 16 class SkCachedData : ::SkNoncopyable { 17 public: 18 SkCachedData(void* mallocData, size_t size); 19 SkCachedData(size_t size, SkDiscardableMemory*); 20 virtual ~SkCachedData(); 21 size()22 size_t size() const { return fSize; } data()23 const void* data() const { return fData; } 24 writable_data()25 void* writable_data() { return fData; } 26 ref()27 void ref() const { this->internalRef(false); } unref()28 void unref() const { this->internalUnref(false); } 29 testing_only_getRefCnt()30 int testing_only_getRefCnt() const { return fRefCnt; } testing_only_isLocked()31 bool testing_only_isLocked() const { return fIsLocked; } testing_only_isInCache()32 bool testing_only_isInCache() const { return fInCache; } 33 diagnostic_only_getDiscardable()34 SkDiscardableMemory* diagnostic_only_getDiscardable() const { 35 return kDiscardableMemory_StorageType == fStorageType ? fStorage.fDM : nullptr; 36 } 37 38 protected: 39 // called when fData changes. could be nullptr. onDataChange(void * oldData,void * newData)40 virtual void onDataChange(void* oldData, void* newData) {} 41 42 private: 43 SkMutex fMutex; // could use a pool of these... 44 45 enum StorageType { 46 kDiscardableMemory_StorageType, 47 kMalloc_StorageType 48 }; 49 50 union { 51 SkDiscardableMemory* fDM; 52 void* fMalloc; 53 } fStorage; 54 void* fData; 55 size_t fSize; 56 int fRefCnt; // low-bit means we're owned by the cache 57 StorageType fStorageType; 58 bool fInCache; 59 bool fIsLocked; 60 61 void internalRef(bool fromCache) const; 62 void internalUnref(bool fromCache) const; 63 64 void inMutexRef(bool fromCache); 65 bool inMutexUnref(bool fromCache); // returns true if we should delete "this" 66 void inMutexLock(); 67 void inMutexUnlock(); 68 69 // called whenever our fData might change (lock or unlock) setData(void * newData)70 void setData(void* newData) { 71 if (newData != fData) { 72 // notify our subclasses of the change 73 this->onDataChange(fData, newData); 74 fData = newData; 75 } 76 } 77 78 class AutoMutexWritable; 79 80 public: 81 #ifdef SK_DEBUG 82 void validate() const; 83 #else 84 void validate() const {} 85 #endif 86 87 /* 88 * Attaching a data to to a SkResourceCache (only one at a time) enables the data to be 89 * unlocked when the cache is the only owner, thus freeing it to be purged (assuming the 90 * data is backed by a SkDiscardableMemory). 91 * 92 * When attached, it also automatically attempts to "lock" the data when the first client 93 * ref's the data (typically from a find(key, visitor) call). 94 * 95 * Thus the data will always be "locked" when a non-cache has a ref on it (whether or not 96 * the lock succeeded to recover the memory -- check data() to see if it is nullptr). 97 */ 98 99 /* 100 * Call when adding this instance to a SkResourceCache::Rec subclass 101 * (typically in the Rec's constructor). 102 */ attachToCacheAndRef()103 void attachToCacheAndRef() const { this->internalRef(true); } 104 105 /* 106 * Call when removing this instance from a SkResourceCache::Rec subclass 107 * (typically in the Rec's destructor). 108 */ detachFromCacheAndUnref()109 void detachFromCacheAndUnref() const { this->internalUnref(true); } 110 }; 111 112 #endif 113