Line data Source code
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 :
22 0 : size_t size() const { return fSize; }
23 0 : const void* data() const { return fData; }
24 :
25 0 : void* writable_data() { return fData; }
26 :
27 0 : void ref() const { this->internalRef(false); }
28 0 : void unref() const { this->internalUnref(false); }
29 :
30 : int testing_only_getRefCnt() const { return fRefCnt; }
31 : bool testing_only_isLocked() const { return fIsLocked; }
32 : bool testing_only_isInCache() const { return fInCache; }
33 :
34 0 : SkDiscardableMemory* diagnostic_only_getDiscardable() const {
35 0 : return kDiscardableMemory_StorageType == fStorageType ? fStorage.fDM : nullptr;
36 : }
37 :
38 : protected:
39 : // called when fData changes. could be nullptr.
40 0 : 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)
70 0 : void setData(void* newData) {
71 0 : if (newData != fData) {
72 : // notify our subclasses of the change
73 0 : this->onDataChange(fData, newData);
74 0 : fData = newData;
75 : }
76 0 : }
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 : */
103 0 : 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 : */
109 0 : void detachFromCacheAndUnref() const { this->internalUnref(true); }
110 : };
111 :
112 : #endif
|