1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/private/SkMalloc.h"
9cb93a386Sopenharmony_ci#include "src/core/SkCachedData.h"
10cb93a386Sopenharmony_ci#include "src/core/SkDiscardableMemory.h"
11cb93a386Sopenharmony_ci
12cb93a386Sopenharmony_ciSkCachedData::SkCachedData(void* data, size_t size)
13cb93a386Sopenharmony_ci    : fData(data)
14cb93a386Sopenharmony_ci    , fSize(size)
15cb93a386Sopenharmony_ci    , fRefCnt(1)
16cb93a386Sopenharmony_ci    , fStorageType(kMalloc_StorageType)
17cb93a386Sopenharmony_ci    , fInCache(false)
18cb93a386Sopenharmony_ci    , fIsLocked(true)
19cb93a386Sopenharmony_ci{
20cb93a386Sopenharmony_ci    fStorage.fMalloc = data;
21cb93a386Sopenharmony_ci}
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_ciSkCachedData::SkCachedData(size_t size, SkDiscardableMemory* dm)
24cb93a386Sopenharmony_ci    : fData(dm->data())
25cb93a386Sopenharmony_ci    , fSize(size)
26cb93a386Sopenharmony_ci    , fRefCnt(1)
27cb93a386Sopenharmony_ci    , fStorageType(kDiscardableMemory_StorageType)
28cb93a386Sopenharmony_ci    , fInCache(false)
29cb93a386Sopenharmony_ci    , fIsLocked(true)
30cb93a386Sopenharmony_ci{
31cb93a386Sopenharmony_ci    fStorage.fDM = dm;
32cb93a386Sopenharmony_ci}
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_ciSkCachedData::~SkCachedData() {
35cb93a386Sopenharmony_ci    switch (fStorageType) {
36cb93a386Sopenharmony_ci        case kMalloc_StorageType:
37cb93a386Sopenharmony_ci            sk_free(fStorage.fMalloc);
38cb93a386Sopenharmony_ci            break;
39cb93a386Sopenharmony_ci        case kDiscardableMemory_StorageType:
40cb93a386Sopenharmony_ci            delete fStorage.fDM;
41cb93a386Sopenharmony_ci            break;
42cb93a386Sopenharmony_ci    }
43cb93a386Sopenharmony_ci}
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ciclass SkCachedData::AutoMutexWritable {
46cb93a386Sopenharmony_cipublic:
47cb93a386Sopenharmony_ci    AutoMutexWritable(const SkCachedData* cd) : fCD(const_cast<SkCachedData*>(cd)) {
48cb93a386Sopenharmony_ci        fCD->fMutex.acquire();
49cb93a386Sopenharmony_ci        fCD->validate();
50cb93a386Sopenharmony_ci    }
51cb93a386Sopenharmony_ci    ~AutoMutexWritable() {
52cb93a386Sopenharmony_ci        fCD->validate();
53cb93a386Sopenharmony_ci        fCD->fMutex.release();
54cb93a386Sopenharmony_ci    }
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ci    SkCachedData* get() { return fCD; }
57cb93a386Sopenharmony_ci    SkCachedData* operator->() { return fCD; }
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_ciprivate:
60cb93a386Sopenharmony_ci    SkCachedData* fCD;
61cb93a386Sopenharmony_ci};
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_civoid SkCachedData::internalRef(bool fromCache) const {
64cb93a386Sopenharmony_ci    AutoMutexWritable(this)->inMutexRef(fromCache);
65cb93a386Sopenharmony_ci}
66cb93a386Sopenharmony_ci
67cb93a386Sopenharmony_civoid SkCachedData::internalUnref(bool fromCache) const {
68cb93a386Sopenharmony_ci    if (AutoMutexWritable(this)->inMutexUnref(fromCache)) {
69cb93a386Sopenharmony_ci        // can't delete inside doInternalUnref, since it is locking a mutex (which we own)
70cb93a386Sopenharmony_ci        delete this;
71cb93a386Sopenharmony_ci    }
72cb93a386Sopenharmony_ci}
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_civoid SkCachedData::inMutexRef(bool fromCache) {
77cb93a386Sopenharmony_ci    if ((1 == fRefCnt) && fInCache) {
78cb93a386Sopenharmony_ci        this->inMutexLock();
79cb93a386Sopenharmony_ci    }
80cb93a386Sopenharmony_ci
81cb93a386Sopenharmony_ci    fRefCnt += 1;
82cb93a386Sopenharmony_ci    if (fromCache) {
83cb93a386Sopenharmony_ci        SkASSERT(!fInCache);
84cb93a386Sopenharmony_ci        fInCache = true;
85cb93a386Sopenharmony_ci    }
86cb93a386Sopenharmony_ci}
87cb93a386Sopenharmony_ci
88cb93a386Sopenharmony_cibool SkCachedData::inMutexUnref(bool fromCache) {
89cb93a386Sopenharmony_ci    switch (--fRefCnt) {
90cb93a386Sopenharmony_ci        case 0:
91cb93a386Sopenharmony_ci            // we're going to be deleted, so we need to be unlocked (for DiscardableMemory)
92cb93a386Sopenharmony_ci            if (fIsLocked) {
93cb93a386Sopenharmony_ci                this->inMutexUnlock();
94cb93a386Sopenharmony_ci            }
95cb93a386Sopenharmony_ci            break;
96cb93a386Sopenharmony_ci        case 1:
97cb93a386Sopenharmony_ci            if (fInCache && !fromCache) {
98cb93a386Sopenharmony_ci                // If we're down to 1 owner, and that owner is the cache, this it is safe
99cb93a386Sopenharmony_ci                // to unlock (and mutate fData) even if the cache is in a different thread,
100cb93a386Sopenharmony_ci                // as the cache is NOT allowed to inspect or use fData.
101cb93a386Sopenharmony_ci                this->inMutexUnlock();
102cb93a386Sopenharmony_ci            }
103cb93a386Sopenharmony_ci            break;
104cb93a386Sopenharmony_ci        default:
105cb93a386Sopenharmony_ci            break;
106cb93a386Sopenharmony_ci    }
107cb93a386Sopenharmony_ci
108cb93a386Sopenharmony_ci    if (fromCache) {
109cb93a386Sopenharmony_ci        SkASSERT(fInCache);
110cb93a386Sopenharmony_ci        fInCache = false;
111cb93a386Sopenharmony_ci    }
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ci    // return true when we need to be deleted
114cb93a386Sopenharmony_ci    return 0 == fRefCnt;
115cb93a386Sopenharmony_ci}
116cb93a386Sopenharmony_ci
117cb93a386Sopenharmony_civoid SkCachedData::inMutexLock() {
118cb93a386Sopenharmony_ci    fMutex.assertHeld();
119cb93a386Sopenharmony_ci
120cb93a386Sopenharmony_ci    SkASSERT(!fIsLocked);
121cb93a386Sopenharmony_ci    fIsLocked = true;
122cb93a386Sopenharmony_ci
123cb93a386Sopenharmony_ci    switch (fStorageType) {
124cb93a386Sopenharmony_ci        case kMalloc_StorageType:
125cb93a386Sopenharmony_ci            this->setData(fStorage.fMalloc);
126cb93a386Sopenharmony_ci            break;
127cb93a386Sopenharmony_ci        case kDiscardableMemory_StorageType:
128cb93a386Sopenharmony_ci            if (fStorage.fDM->lock()) {
129cb93a386Sopenharmony_ci                void* ptr = fStorage.fDM->data();
130cb93a386Sopenharmony_ci                SkASSERT(ptr);
131cb93a386Sopenharmony_ci                this->setData(ptr);
132cb93a386Sopenharmony_ci            } else {
133cb93a386Sopenharmony_ci                this->setData(nullptr);   // signal failure to lock, contents are gone
134cb93a386Sopenharmony_ci            }
135cb93a386Sopenharmony_ci            break;
136cb93a386Sopenharmony_ci    }
137cb93a386Sopenharmony_ci}
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_civoid SkCachedData::inMutexUnlock() {
140cb93a386Sopenharmony_ci    fMutex.assertHeld();
141cb93a386Sopenharmony_ci
142cb93a386Sopenharmony_ci    SkASSERT(fIsLocked);
143cb93a386Sopenharmony_ci    fIsLocked = false;
144cb93a386Sopenharmony_ci
145cb93a386Sopenharmony_ci    switch (fStorageType) {
146cb93a386Sopenharmony_ci        case kMalloc_StorageType:
147cb93a386Sopenharmony_ci            // nothing to do/check
148cb93a386Sopenharmony_ci            break;
149cb93a386Sopenharmony_ci        case kDiscardableMemory_StorageType:
150cb93a386Sopenharmony_ci            if (fData) {    // did the previous lock succeed?
151cb93a386Sopenharmony_ci                fStorage.fDM->unlock();
152cb93a386Sopenharmony_ci            }
153cb93a386Sopenharmony_ci            break;
154cb93a386Sopenharmony_ci    }
155cb93a386Sopenharmony_ci    this->setData(nullptr);   // signal that we're in an unlocked state
156cb93a386Sopenharmony_ci}
157cb93a386Sopenharmony_ci
158cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////
159cb93a386Sopenharmony_ci
160cb93a386Sopenharmony_ci#ifdef SK_DEBUG
161cb93a386Sopenharmony_civoid SkCachedData::validate() const {
162cb93a386Sopenharmony_ci    if (fIsLocked) {
163cb93a386Sopenharmony_ci        SkASSERT((fInCache && fRefCnt > 1) || !fInCache);
164cb93a386Sopenharmony_ci        switch (fStorageType) {
165cb93a386Sopenharmony_ci            case kMalloc_StorageType:
166cb93a386Sopenharmony_ci                SkASSERT(fData == fStorage.fMalloc);
167cb93a386Sopenharmony_ci                break;
168cb93a386Sopenharmony_ci            case kDiscardableMemory_StorageType:
169cb93a386Sopenharmony_ci                // fData can be null or the actual value, depending if DM's lock succeeded
170cb93a386Sopenharmony_ci                break;
171cb93a386Sopenharmony_ci        }
172cb93a386Sopenharmony_ci    } else {
173cb93a386Sopenharmony_ci        SkASSERT((fInCache && 1 == fRefCnt) || (0 == fRefCnt));
174cb93a386Sopenharmony_ci        SkASSERT(nullptr == fData);
175cb93a386Sopenharmony_ci    }
176cb93a386Sopenharmony_ci}
177cb93a386Sopenharmony_ci#endif
178