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
15class SkDiscardableMemory;
16
17class SkCachedData : ::SkNoncopyable {
18public:
19 SkCachedData(void* mallocData, size_t size);
20 SkCachedData(size_t size, SkDiscardableMemory*);
21 virtual ~SkCachedData();
22
23 size_t size() const { return fSize; }
24 const void* data() const { return fData; }
25
26 void* writable_data() { return fData; }
27
28 void ref() const { this->internalRef(false); }
29 void unref() const { this->internalUnref(false); }
30
31 int testing_only_getRefCnt() const { return fRefCnt; }
32 bool testing_only_isLocked() const { return fIsLocked; }
33 bool testing_only_isInCache() const { return fInCache; }
34
35 SkDiscardableMemory* diagnostic_only_getDiscardable() const {
36 return kDiscardableMemory_StorageType == fStorageType ? fStorage.fDM : nullptr;
37 }
38
39protected:
40 // called when fData changes. could be nullptr.
41 virtual void onDataChange(void* oldData, void* newData) {}
42
43private:
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)
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
81public:
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 */
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 */
110 void detachFromCacheAndUnref() const { this->internalUnref(true); }
111};
112
113#endif
114