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