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