Home | History | Annotate | Download | only in core
      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     size_t size() const { return fSize; }
     23     const void* data() const { return fData; }
     24 
     25     void* writable_data() { return fData; }
     26 
     27     void ref() const { this->internalRef(false); }
     28     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     SkDiscardableMemory* diagnostic_only_getDiscardable() const {
     35         return kDiscardableMemory_StorageType == fStorageType ? fStorage.fDM : nullptr;
     36     }
     37 
     38 protected:
     39     // called when fData changes. could be nullptr.
     40     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     void setData(void* newData) {
     71         if (newData != fData) {
     72             // notify our subclasses of the change
     73             this->onDataChange(fData, newData);
     74             fData = newData;
     75         }
     76     }
     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     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     void detachFromCacheAndUnref() const { this->internalUnref(true); }
    110 };
    111 
    112 #endif
    113