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/SkMutex.h"
13 #include "include/private/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