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