OLD | NEW |
(Empty) | |
| 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 #include "SkCachedData_priv.h" |
| 9 #include "SkRefCnt.h" |
| 10 #include "SkDiscardableMemory.h" |
| 11 |
| 12 SkCachedData::SkCachedData(void* data, size_t size) |
| 13 : fData(data) |
| 14 , fSize(size) |
| 15 , fRefCnt(2) // 1 owner, not in cache |
| 16 { |
| 17 fStorage.fMalloc = data; |
| 18 fStorageType = kMalloc_StorageType; |
| 19 } |
| 20 |
| 21 SkCachedData::SkCachedData(size_t size, SkDiscardableMemory* dm) |
| 22 : fData(dm->data()) |
| 23 , fSize(size) |
| 24 , fRefCnt(2) // 1 owner, not in cache |
| 25 { |
| 26 fStorage.fDM = dm; |
| 27 fStorageType = kDiscardableMemory_StorageType; |
| 28 } |
| 29 |
| 30 SkCachedData::~SkCachedData() { |
| 31 switch (fStorageType) { |
| 32 case kMalloc_StorageType: |
| 33 sk_free(fStorage.fMalloc); |
| 34 break; |
| 35 case kDiscardableMemory_StorageType: |
| 36 SkDELETE(fStorage.fDM); |
| 37 break; |
| 38 } |
| 39 } |
| 40 |
| 41 void SkCachedData::internalRef(bool fromCache) const { |
| 42 SkCachedData* writable = const_cast<SkCachedData*>(this); |
| 43 SkAutoMutexAcquire ama(writable->get_mutex()); |
| 44 |
| 45 int32_t amount; |
| 46 if (fromCache) { |
| 47 // assert that we are not already attached (i.e. the low-bit is 0) |
| 48 SkASSERT(0 == (writable->fRefCnt & 1)); |
| 49 amount = 3; |
| 50 } else { |
| 51 // from client |
| 52 amount = 2; |
| 53 } |
| 54 |
| 55 const int32_t new_count = (writable->fRefCnt += amount); |
| 56 const int new_owners = new_count >> 1; |
| 57 const int in_cache = new_count & 1; |
| 58 |
| 59 SkASSERT(new_owners >= 2); |
| 60 |
| 61 if (2 == new_owners && !fromCache) { |
| 62 if (in_cache) { |
| 63 writable->in_mutex_lock(); |
| 64 } |
| 65 } |
| 66 } |
| 67 |
| 68 bool SkCachedData::doInternalUnref(bool fromCache) const { |
| 69 SkCachedData* writable = const_cast<SkCachedData*>(this); |
| 70 SkAutoMutexAcquire ama(writable->get_mutex()); |
| 71 |
| 72 int32_t amount; |
| 73 if (fromCache) { |
| 74 // assert that we are already attached (i.e. the low-bit is 1) |
| 75 SkASSERT(1 == (fRefCnt & 1)); |
| 76 amount = 3; |
| 77 } else { |
| 78 // from client |
| 79 amount = 2; |
| 80 } |
| 81 |
| 82 const int32_t new_count = (writable->fRefCnt -= amount); |
| 83 const int new_owners = new_count >> 1; |
| 84 const int in_cache = new_count & 1; |
| 85 |
| 86 switch (new_owners) { |
| 87 case 0: |
| 88 writable->in_mutex_prepareToDelete(); |
| 89 break; |
| 90 case 1: |
| 91 if (in_cache) { |
| 92 // If we're down to 1 owner, and that owner is the cache, this i
t is safe |
| 93 // to unlock (and mutate fData) even if the cache is in a differ
ent thread, |
| 94 // as the cache is NOT allowed to inspect or use fData. |
| 95 writable->in_mutex_unlock(); |
| 96 } |
| 97 break; |
| 98 default: |
| 99 break; |
| 100 } |
| 101 return 0 == new_owners; |
| 102 } |
| 103 |
| 104 void SkCachedData::internalUnref(bool fromCache) const { |
| 105 if (this->doInternalUnref(fromCache)) { |
| 106 // can't delete inside doInternalUnref, since it is locking a mutex (whi
ch we own) |
| 107 SkDELETE(this); |
| 108 } |
| 109 } |
| 110 |
| 111 void SkCachedData::in_mutex_lock() { |
| 112 this->assert_in_mutex(); |
| 113 |
| 114 switch (fStorageType) { |
| 115 case kMalloc_StorageType: |
| 116 this->setData(fStorage.fMalloc); |
| 117 break; |
| 118 case kDiscardableMemory_StorageType: |
| 119 if (fStorage.fDM->lock()) { |
| 120 this->setData(fStorage.fDM->data()); |
| 121 } else { |
| 122 this->setData(NULL); // signal failure to lock, contents are g
one |
| 123 } |
| 124 break; |
| 125 } |
| 126 } |
| 127 |
| 128 void SkCachedData::in_mutex_unlock() { |
| 129 this->assert_in_mutex(); |
| 130 |
| 131 switch (fStorageType) { |
| 132 case kMalloc_StorageType: |
| 133 // nothing to do/check |
| 134 break; |
| 135 case kDiscardableMemory_StorageType: |
| 136 if (fData) { // did the previous lock succeed? |
| 137 fStorage.fDM->unlock(); |
| 138 } |
| 139 break; |
| 140 } |
| 141 this->setData(NULL); // signal that we're in an unlocked state |
| 142 } |
| 143 |
| 144 void SkCachedData::in_mutex_prepareToDelete() { |
| 145 this->assert_in_mutex(); |
| 146 |
| 147 switch (fStorageType) { |
| 148 case kMalloc_StorageType: |
| 149 // nothing to do/check |
| 150 break; |
| 151 case kDiscardableMemory_StorageType: |
| 152 // discardable request that it be unlocked before being deleted |
| 153 if (fData) { |
| 154 fStorage.fDM->unlock(); |
| 155 } |
| 156 break; |
| 157 } |
| 158 } |
| 159 |
OLD | NEW |