19d93c2ebb31bf996905532446644f242339a774ereed/*
29d93c2ebb31bf996905532446644f242339a774ereed * Copyright 2014 Google Inc.
39d93c2ebb31bf996905532446644f242339a774ereed *
49d93c2ebb31bf996905532446644f242339a774ereed * Use of this source code is governed by a BSD-style license that can be
59d93c2ebb31bf996905532446644f242339a774ereed * found in the LICENSE file.
69d93c2ebb31bf996905532446644f242339a774ereed */
79d93c2ebb31bf996905532446644f242339a774ereed
89d93c2ebb31bf996905532446644f242339a774ereed#include "SkCachedData.h"
99d93c2ebb31bf996905532446644f242339a774ereed#include "SkDiscardableMemory.h"
109d93c2ebb31bf996905532446644f242339a774ereed
119d93c2ebb31bf996905532446644f242339a774ereed//#define TRACK_CACHEDDATA_LIFETIME
129d93c2ebb31bf996905532446644f242339a774ereed
139d93c2ebb31bf996905532446644f242339a774ereed#ifdef TRACK_CACHEDDATA_LIFETIME
149d93c2ebb31bf996905532446644f242339a774ereedstatic int32_t gCachedDataCounter;
159d93c2ebb31bf996905532446644f242339a774ereed
169d93c2ebb31bf996905532446644f242339a774ereedstatic void inc() {
179d93c2ebb31bf996905532446644f242339a774ereed    int32_t oldCount = sk_atomic_inc(&gCachedDataCounter);
189d93c2ebb31bf996905532446644f242339a774ereed    SkDebugf("SkCachedData inc %d\n", oldCount + 1);
199d93c2ebb31bf996905532446644f242339a774ereed}
209d93c2ebb31bf996905532446644f242339a774ereed
219d93c2ebb31bf996905532446644f242339a774ereedstatic void dec() {
229d93c2ebb31bf996905532446644f242339a774ereed    int32_t oldCount = sk_atomic_dec(&gCachedDataCounter);
239d93c2ebb31bf996905532446644f242339a774ereed    SkDebugf("SkCachedData dec %d\n", oldCount - 1);
249d93c2ebb31bf996905532446644f242339a774ereed}
259d93c2ebb31bf996905532446644f242339a774ereed#else
269d93c2ebb31bf996905532446644f242339a774ereedstatic void inc() {}
279d93c2ebb31bf996905532446644f242339a774ereedstatic void dec() {}
289d93c2ebb31bf996905532446644f242339a774ereed#endif
299d93c2ebb31bf996905532446644f242339a774ereed
309d93c2ebb31bf996905532446644f242339a774ereedSkCachedData::SkCachedData(void* data, size_t size)
319d93c2ebb31bf996905532446644f242339a774ereed    : fData(data)
329d93c2ebb31bf996905532446644f242339a774ereed    , fSize(size)
339d93c2ebb31bf996905532446644f242339a774ereed    , fRefCnt(1)
349d93c2ebb31bf996905532446644f242339a774ereed    , fStorageType(kMalloc_StorageType)
359d93c2ebb31bf996905532446644f242339a774ereed    , fInCache(false)
369d93c2ebb31bf996905532446644f242339a774ereed    , fIsLocked(true)
379d93c2ebb31bf996905532446644f242339a774ereed{
389d93c2ebb31bf996905532446644f242339a774ereed    fStorage.fMalloc = data;
399d93c2ebb31bf996905532446644f242339a774ereed    inc();
409d93c2ebb31bf996905532446644f242339a774ereed}
419d93c2ebb31bf996905532446644f242339a774ereed
429d93c2ebb31bf996905532446644f242339a774ereedSkCachedData::SkCachedData(size_t size, SkDiscardableMemory* dm)
439d93c2ebb31bf996905532446644f242339a774ereed    : fData(dm->data())
449d93c2ebb31bf996905532446644f242339a774ereed    , fSize(size)
459d93c2ebb31bf996905532446644f242339a774ereed    , fRefCnt(1)
469d93c2ebb31bf996905532446644f242339a774ereed    , fStorageType(kDiscardableMemory_StorageType)
479d93c2ebb31bf996905532446644f242339a774ereed    , fInCache(false)
489d93c2ebb31bf996905532446644f242339a774ereed    , fIsLocked(true)
499d93c2ebb31bf996905532446644f242339a774ereed{
509d93c2ebb31bf996905532446644f242339a774ereed    fStorage.fDM = dm;
519d93c2ebb31bf996905532446644f242339a774ereed    inc();
529d93c2ebb31bf996905532446644f242339a774ereed}
539d93c2ebb31bf996905532446644f242339a774ereed
549d93c2ebb31bf996905532446644f242339a774ereedSkCachedData::~SkCachedData() {
559d93c2ebb31bf996905532446644f242339a774ereed    switch (fStorageType) {
569d93c2ebb31bf996905532446644f242339a774ereed        case kMalloc_StorageType:
579d93c2ebb31bf996905532446644f242339a774ereed            sk_free(fStorage.fMalloc);
589d93c2ebb31bf996905532446644f242339a774ereed            break;
599d93c2ebb31bf996905532446644f242339a774ereed        case kDiscardableMemory_StorageType:
602880df2609eba09b555ca37be04b6ad89290c765Tom Hudson            delete fStorage.fDM;
619d93c2ebb31bf996905532446644f242339a774ereed            break;
629d93c2ebb31bf996905532446644f242339a774ereed    }
639d93c2ebb31bf996905532446644f242339a774ereed    dec();
649d93c2ebb31bf996905532446644f242339a774ereed}
659d93c2ebb31bf996905532446644f242339a774ereed
669d93c2ebb31bf996905532446644f242339a774ereedclass SkCachedData::AutoMutexWritable {
679d93c2ebb31bf996905532446644f242339a774ereedpublic:
689d93c2ebb31bf996905532446644f242339a774ereed    AutoMutexWritable(const SkCachedData* cd) : fCD(const_cast<SkCachedData*>(cd)) {
699d93c2ebb31bf996905532446644f242339a774ereed        fCD->fMutex.acquire();
709d93c2ebb31bf996905532446644f242339a774ereed        fCD->validate();
719d93c2ebb31bf996905532446644f242339a774ereed    }
729d93c2ebb31bf996905532446644f242339a774ereed    ~AutoMutexWritable() {
739d93c2ebb31bf996905532446644f242339a774ereed        fCD->validate();
749d93c2ebb31bf996905532446644f242339a774ereed        fCD->fMutex.release();
759d93c2ebb31bf996905532446644f242339a774ereed    }
769d93c2ebb31bf996905532446644f242339a774ereed
779d93c2ebb31bf996905532446644f242339a774ereed    SkCachedData* get() { return fCD; }
789d93c2ebb31bf996905532446644f242339a774ereed    SkCachedData* operator->() { return fCD; }
799d93c2ebb31bf996905532446644f242339a774ereed
809d93c2ebb31bf996905532446644f242339a774ereedprivate:
819d93c2ebb31bf996905532446644f242339a774ereed    SkCachedData* fCD;
829d93c2ebb31bf996905532446644f242339a774ereed};
839d93c2ebb31bf996905532446644f242339a774ereed
849d93c2ebb31bf996905532446644f242339a774ereedvoid SkCachedData::internalRef(bool fromCache) const {
859d93c2ebb31bf996905532446644f242339a774ereed    AutoMutexWritable(this)->inMutexRef(fromCache);
869d93c2ebb31bf996905532446644f242339a774ereed}
879d93c2ebb31bf996905532446644f242339a774ereed
889d93c2ebb31bf996905532446644f242339a774ereedvoid SkCachedData::internalUnref(bool fromCache) const {
899d93c2ebb31bf996905532446644f242339a774ereed    if (AutoMutexWritable(this)->inMutexUnref(fromCache)) {
909d93c2ebb31bf996905532446644f242339a774ereed        // can't delete inside doInternalUnref, since it is locking a mutex (which we own)
912880df2609eba09b555ca37be04b6ad89290c765Tom Hudson        delete this;
929d93c2ebb31bf996905532446644f242339a774ereed    }
939d93c2ebb31bf996905532446644f242339a774ereed}
949d93c2ebb31bf996905532446644f242339a774ereed
959d93c2ebb31bf996905532446644f242339a774ereed///////////////////////////////////////////////////////////////////////////////////////////////////
969d93c2ebb31bf996905532446644f242339a774ereed
979d93c2ebb31bf996905532446644f242339a774ereedvoid SkCachedData::inMutexRef(bool fromCache) {
989d93c2ebb31bf996905532446644f242339a774ereed    if ((1 == fRefCnt) && fInCache) {
999d93c2ebb31bf996905532446644f242339a774ereed        this->inMutexLock();
1009d93c2ebb31bf996905532446644f242339a774ereed    }
1019d93c2ebb31bf996905532446644f242339a774ereed
1029d93c2ebb31bf996905532446644f242339a774ereed    fRefCnt += 1;
1039d93c2ebb31bf996905532446644f242339a774ereed    if (fromCache) {
1049d93c2ebb31bf996905532446644f242339a774ereed        SkASSERT(!fInCache);
1059d93c2ebb31bf996905532446644f242339a774ereed        fInCache = true;
1069d93c2ebb31bf996905532446644f242339a774ereed    }
1079d93c2ebb31bf996905532446644f242339a774ereed}
1089d93c2ebb31bf996905532446644f242339a774ereed
1099d93c2ebb31bf996905532446644f242339a774ereedbool SkCachedData::inMutexUnref(bool fromCache) {
1109d93c2ebb31bf996905532446644f242339a774ereed    switch (--fRefCnt) {
1119d93c2ebb31bf996905532446644f242339a774ereed        case 0:
1129d93c2ebb31bf996905532446644f242339a774ereed            // we're going to be deleted, so we need to be unlocked (for DiscardableMemory)
1139d93c2ebb31bf996905532446644f242339a774ereed            if (fIsLocked) {
1149d93c2ebb31bf996905532446644f242339a774ereed                this->inMutexUnlock();
1159d93c2ebb31bf996905532446644f242339a774ereed            }
1169d93c2ebb31bf996905532446644f242339a774ereed            break;
1179d93c2ebb31bf996905532446644f242339a774ereed        case 1:
1189d93c2ebb31bf996905532446644f242339a774ereed            if (fInCache && !fromCache) {
1199d93c2ebb31bf996905532446644f242339a774ereed                // If we're down to 1 owner, and that owner is the cache, this it is safe
1209d93c2ebb31bf996905532446644f242339a774ereed                // to unlock (and mutate fData) even if the cache is in a different thread,
1219d93c2ebb31bf996905532446644f242339a774ereed                // as the cache is NOT allowed to inspect or use fData.
1229d93c2ebb31bf996905532446644f242339a774ereed                this->inMutexUnlock();
1239d93c2ebb31bf996905532446644f242339a774ereed            }
1249d93c2ebb31bf996905532446644f242339a774ereed            break;
1259d93c2ebb31bf996905532446644f242339a774ereed        default:
1269d93c2ebb31bf996905532446644f242339a774ereed            break;
1279d93c2ebb31bf996905532446644f242339a774ereed    }
1289d93c2ebb31bf996905532446644f242339a774ereed
1299d93c2ebb31bf996905532446644f242339a774ereed    if (fromCache) {
1309d93c2ebb31bf996905532446644f242339a774ereed        SkASSERT(fInCache);
1319d93c2ebb31bf996905532446644f242339a774ereed        fInCache = false;
1329d93c2ebb31bf996905532446644f242339a774ereed    }
1339d93c2ebb31bf996905532446644f242339a774ereed
1349d93c2ebb31bf996905532446644f242339a774ereed    // return true when we need to be deleted
1359d93c2ebb31bf996905532446644f242339a774ereed    return 0 == fRefCnt;
1369d93c2ebb31bf996905532446644f242339a774ereed}
1379d93c2ebb31bf996905532446644f242339a774ereed
1389d93c2ebb31bf996905532446644f242339a774ereedvoid SkCachedData::inMutexLock() {
1399d93c2ebb31bf996905532446644f242339a774ereed    fMutex.assertHeld();
1409d93c2ebb31bf996905532446644f242339a774ereed
1419d93c2ebb31bf996905532446644f242339a774ereed    SkASSERT(!fIsLocked);
1429d93c2ebb31bf996905532446644f242339a774ereed    fIsLocked = true;
1439d93c2ebb31bf996905532446644f242339a774ereed
1449d93c2ebb31bf996905532446644f242339a774ereed    switch (fStorageType) {
1459d93c2ebb31bf996905532446644f242339a774ereed        case kMalloc_StorageType:
1469d93c2ebb31bf996905532446644f242339a774ereed            this->setData(fStorage.fMalloc);
1479d93c2ebb31bf996905532446644f242339a774ereed            break;
1489d93c2ebb31bf996905532446644f242339a774ereed        case kDiscardableMemory_StorageType:
1499d93c2ebb31bf996905532446644f242339a774ereed            if (fStorage.fDM->lock()) {
1509d93c2ebb31bf996905532446644f242339a774ereed                void* ptr = fStorage.fDM->data();
1519d93c2ebb31bf996905532446644f242339a774ereed                SkASSERT(ptr);
1529d93c2ebb31bf996905532446644f242339a774ereed                this->setData(ptr);
1539d93c2ebb31bf996905532446644f242339a774ereed            } else {
1542880df2609eba09b555ca37be04b6ad89290c765Tom Hudson                this->setData(nullptr);   // signal failure to lock, contents are gone
1559d93c2ebb31bf996905532446644f242339a774ereed            }
1569d93c2ebb31bf996905532446644f242339a774ereed            break;
1579d93c2ebb31bf996905532446644f242339a774ereed    }
1589d93c2ebb31bf996905532446644f242339a774ereed}
1599d93c2ebb31bf996905532446644f242339a774ereed
1609d93c2ebb31bf996905532446644f242339a774ereedvoid SkCachedData::inMutexUnlock() {
1619d93c2ebb31bf996905532446644f242339a774ereed    fMutex.assertHeld();
1629d93c2ebb31bf996905532446644f242339a774ereed
1639d93c2ebb31bf996905532446644f242339a774ereed    SkASSERT(fIsLocked);
1649d93c2ebb31bf996905532446644f242339a774ereed    fIsLocked = false;
1659d93c2ebb31bf996905532446644f242339a774ereed
1669d93c2ebb31bf996905532446644f242339a774ereed    switch (fStorageType) {
1679d93c2ebb31bf996905532446644f242339a774ereed        case kMalloc_StorageType:
1689d93c2ebb31bf996905532446644f242339a774ereed            // nothing to do/check
1699d93c2ebb31bf996905532446644f242339a774ereed            break;
1709d93c2ebb31bf996905532446644f242339a774ereed        case kDiscardableMemory_StorageType:
1719d93c2ebb31bf996905532446644f242339a774ereed            if (fData) {    // did the previous lock succeed?
1729d93c2ebb31bf996905532446644f242339a774ereed                fStorage.fDM->unlock();
1739d93c2ebb31bf996905532446644f242339a774ereed            }
1749d93c2ebb31bf996905532446644f242339a774ereed            break;
1759d93c2ebb31bf996905532446644f242339a774ereed    }
1762880df2609eba09b555ca37be04b6ad89290c765Tom Hudson    this->setData(nullptr);   // signal that we're in an unlocked state
1779d93c2ebb31bf996905532446644f242339a774ereed}
1789d93c2ebb31bf996905532446644f242339a774ereed
1799d93c2ebb31bf996905532446644f242339a774ereed///////////////////////////////////////////////////////////////////////////////////////////////////
1809d93c2ebb31bf996905532446644f242339a774ereed
1819d93c2ebb31bf996905532446644f242339a774ereed#ifdef SK_DEBUG
1829d93c2ebb31bf996905532446644f242339a774ereedvoid SkCachedData::validate() const {
1839d93c2ebb31bf996905532446644f242339a774ereed    if (fIsLocked) {
1849d93c2ebb31bf996905532446644f242339a774ereed        SkASSERT((fInCache && fRefCnt > 1) || !fInCache);
1859d93c2ebb31bf996905532446644f242339a774ereed        switch (fStorageType) {
1869d93c2ebb31bf996905532446644f242339a774ereed            case kMalloc_StorageType:
1879d93c2ebb31bf996905532446644f242339a774ereed                SkASSERT(fData == fStorage.fMalloc);
1889d93c2ebb31bf996905532446644f242339a774ereed                break;
1899d93c2ebb31bf996905532446644f242339a774ereed            case kDiscardableMemory_StorageType:
1909d93c2ebb31bf996905532446644f242339a774ereed                // fData can be null or the actual value, depending if DM's lock succeeded
1919d93c2ebb31bf996905532446644f242339a774ereed                break;
1929d93c2ebb31bf996905532446644f242339a774ereed        }
1939d93c2ebb31bf996905532446644f242339a774ereed    } else {
1949d93c2ebb31bf996905532446644f242339a774ereed        SkASSERT((fInCache && 1 == fRefCnt) || (0 == fRefCnt));
1952880df2609eba09b555ca37be04b6ad89290c765Tom Hudson        SkASSERT(nullptr == fData);
1969d93c2ebb31bf996905532446644f242339a774ereed    }
1979d93c2ebb31bf996905532446644f242339a774ereed}
1989d93c2ebb31bf996905532446644f242339a774ereed#endif
199