9d524f22bf
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1842753002 Review URL: https://codereview.chromium.org/1842753002
199 lines
5.0 KiB
C++
199 lines
5.0 KiB
C++
/*
|
|
* Copyright 2014 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "SkCachedData.h"
|
|
#include "SkDiscardableMemory.h"
|
|
|
|
//#define TRACK_CACHEDDATA_LIFETIME
|
|
|
|
#ifdef TRACK_CACHEDDATA_LIFETIME
|
|
static int32_t gCachedDataCounter;
|
|
|
|
static void inc() {
|
|
int32_t oldCount = sk_atomic_inc(&gCachedDataCounter);
|
|
SkDebugf("SkCachedData inc %d\n", oldCount + 1);
|
|
}
|
|
|
|
static void dec() {
|
|
int32_t oldCount = sk_atomic_dec(&gCachedDataCounter);
|
|
SkDebugf("SkCachedData dec %d\n", oldCount - 1);
|
|
}
|
|
#else
|
|
static void inc() {}
|
|
static void dec() {}
|
|
#endif
|
|
|
|
SkCachedData::SkCachedData(void* data, size_t size)
|
|
: fData(data)
|
|
, fSize(size)
|
|
, fRefCnt(1)
|
|
, fStorageType(kMalloc_StorageType)
|
|
, fInCache(false)
|
|
, fIsLocked(true)
|
|
{
|
|
fStorage.fMalloc = data;
|
|
inc();
|
|
}
|
|
|
|
SkCachedData::SkCachedData(size_t size, SkDiscardableMemory* dm)
|
|
: fData(dm->data())
|
|
, fSize(size)
|
|
, fRefCnt(1)
|
|
, fStorageType(kDiscardableMemory_StorageType)
|
|
, fInCache(false)
|
|
, fIsLocked(true)
|
|
{
|
|
fStorage.fDM = dm;
|
|
inc();
|
|
}
|
|
|
|
SkCachedData::~SkCachedData() {
|
|
switch (fStorageType) {
|
|
case kMalloc_StorageType:
|
|
sk_free(fStorage.fMalloc);
|
|
break;
|
|
case kDiscardableMemory_StorageType:
|
|
delete fStorage.fDM;
|
|
break;
|
|
}
|
|
dec();
|
|
}
|
|
|
|
class SkCachedData::AutoMutexWritable {
|
|
public:
|
|
AutoMutexWritable(const SkCachedData* cd) : fCD(const_cast<SkCachedData*>(cd)) {
|
|
fCD->fMutex.acquire();
|
|
fCD->validate();
|
|
}
|
|
~AutoMutexWritable() {
|
|
fCD->validate();
|
|
fCD->fMutex.release();
|
|
}
|
|
|
|
SkCachedData* get() { return fCD; }
|
|
SkCachedData* operator->() { return fCD; }
|
|
|
|
private:
|
|
SkCachedData* fCD;
|
|
};
|
|
|
|
void SkCachedData::internalRef(bool fromCache) const {
|
|
AutoMutexWritable(this)->inMutexRef(fromCache);
|
|
}
|
|
|
|
void SkCachedData::internalUnref(bool fromCache) const {
|
|
if (AutoMutexWritable(this)->inMutexUnref(fromCache)) {
|
|
// can't delete inside doInternalUnref, since it is locking a mutex (which we own)
|
|
delete this;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SkCachedData::inMutexRef(bool fromCache) {
|
|
if ((1 == fRefCnt) && fInCache) {
|
|
this->inMutexLock();
|
|
}
|
|
|
|
fRefCnt += 1;
|
|
if (fromCache) {
|
|
SkASSERT(!fInCache);
|
|
fInCache = true;
|
|
}
|
|
}
|
|
|
|
bool SkCachedData::inMutexUnref(bool fromCache) {
|
|
switch (--fRefCnt) {
|
|
case 0:
|
|
// we're going to be deleted, so we need to be unlocked (for DiscardableMemory)
|
|
if (fIsLocked) {
|
|
this->inMutexUnlock();
|
|
}
|
|
break;
|
|
case 1:
|
|
if (fInCache && !fromCache) {
|
|
// If we're down to 1 owner, and that owner is the cache, this it is safe
|
|
// to unlock (and mutate fData) even if the cache is in a different thread,
|
|
// as the cache is NOT allowed to inspect or use fData.
|
|
this->inMutexUnlock();
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (fromCache) {
|
|
SkASSERT(fInCache);
|
|
fInCache = false;
|
|
}
|
|
|
|
// return true when we need to be deleted
|
|
return 0 == fRefCnt;
|
|
}
|
|
|
|
void SkCachedData::inMutexLock() {
|
|
fMutex.assertHeld();
|
|
|
|
SkASSERT(!fIsLocked);
|
|
fIsLocked = true;
|
|
|
|
switch (fStorageType) {
|
|
case kMalloc_StorageType:
|
|
this->setData(fStorage.fMalloc);
|
|
break;
|
|
case kDiscardableMemory_StorageType:
|
|
if (fStorage.fDM->lock()) {
|
|
void* ptr = fStorage.fDM->data();
|
|
SkASSERT(ptr);
|
|
this->setData(ptr);
|
|
} else {
|
|
this->setData(nullptr); // signal failure to lock, contents are gone
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void SkCachedData::inMutexUnlock() {
|
|
fMutex.assertHeld();
|
|
|
|
SkASSERT(fIsLocked);
|
|
fIsLocked = false;
|
|
|
|
switch (fStorageType) {
|
|
case kMalloc_StorageType:
|
|
// nothing to do/check
|
|
break;
|
|
case kDiscardableMemory_StorageType:
|
|
if (fData) { // did the previous lock succeed?
|
|
fStorage.fDM->unlock();
|
|
}
|
|
break;
|
|
}
|
|
this->setData(nullptr); // signal that we're in an unlocked state
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef SK_DEBUG
|
|
void SkCachedData::validate() const {
|
|
if (fIsLocked) {
|
|
SkASSERT((fInCache && fRefCnt > 1) || !fInCache);
|
|
switch (fStorageType) {
|
|
case kMalloc_StorageType:
|
|
SkASSERT(fData == fStorage.fMalloc);
|
|
break;
|
|
case kDiscardableMemory_StorageType:
|
|
// fData can be null or the actual value, depending if DM's lock succeeded
|
|
break;
|
|
}
|
|
} else {
|
|
SkASSERT((fInCache && 1 == fRefCnt) || (0 == fRefCnt));
|
|
SkASSERT(nullptr == fData);
|
|
}
|
|
}
|
|
#endif
|