| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2013 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 "SkAshmemImageCache.h" | |
| 9 #include "SkThread.h" | |
| 10 | |
| 11 #ifdef SK_DEBUG | |
| 12 #include "SkTSearch.h" | |
| 13 #endif | |
| 14 | |
| 15 #include "android/ashmem.h" | |
| 16 #include <sys/mman.h> | |
| 17 #include <unistd.h> | |
| 18 | |
| 19 | |
| 20 SkAshmemImageCache::SkAshmemImageCache() {} | |
| 21 | |
| 22 SK_DECLARE_STATIC_MUTEX(gAshmemMutex); | |
| 23 | |
| 24 SkAshmemImageCache* SkAshmemImageCache::GetAshmemImageCache() { | |
| 25 SkAutoMutexAcquire ac(&gAshmemMutex); | |
| 26 static SkAshmemImageCache gCache; | |
| 27 return &gCache; | |
| 28 } | |
| 29 | |
| 30 #ifdef SK_DEBUG | |
| 31 SkAshmemImageCache::~SkAshmemImageCache() { | |
| 32 SkASSERT(fRecs.count() == 0); | |
| 33 } | |
| 34 #endif | |
| 35 | |
| 36 // ashmem likes lengths on page boundaries. | |
| 37 static size_t roundToPageSize(size_t size) { | |
| 38 const size_t mask = getpagesize() - 1; | |
| 39 size_t newSize = (size + mask) & ~mask; | |
| 40 return newSize; | |
| 41 } | |
| 42 | |
| 43 void* SkAshmemImageCache::allocAndPinCache(size_t bytes, intptr_t* ID) { | |
| 44 SkASSERT(ID != NULL); | |
| 45 | |
| 46 SkAutoMutexAcquire ac(&gAshmemMutex); | |
| 47 | |
| 48 if (*ID != SkImageCache::UNINITIALIZED_ID) { | |
| 49 // This rec was previously allocated, but pinCache subsequently | |
| 50 // failed. | |
| 51 AshmemRec* pRec = reinterpret_cast<AshmemRec*>(*ID); | |
| 52 SkASSERT(roundToPageSize(bytes) == pRec->fSize); | |
| 53 SkASSERT(pRec->fFD != -1); | |
| 54 (void) ashmem_pin_region(pRec->fFD, 0, 0); | |
| 55 #ifdef SK_DEBUG | |
| 56 pRec->fPinned = true; | |
| 57 #endif | |
| 58 return pRec->fAddr; | |
| 59 } | |
| 60 | |
| 61 AshmemRec rec; | |
| 62 rec.fSize = roundToPageSize(bytes); | |
| 63 | |
| 64 rec.fFD = ashmem_create_region(NULL, rec.fSize); | |
| 65 if (-1 == rec.fFD) { | |
| 66 SkDebugf("ashmem_create_region failed\n"); | |
| 67 return NULL; | |
| 68 } | |
| 69 int err = ashmem_set_prot_region(rec.fFD, PROT_READ | PROT_WRITE); | |
| 70 if (err != 0) { | |
| 71 SkDebugf("ashmem_set_prot_region failed\n"); | |
| 72 close(rec.fFD); | |
| 73 return NULL; | |
| 74 } | |
| 75 rec.fAddr = mmap(NULL, rec.fSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, rec.f
FD, 0); | |
| 76 if (-1 == (long) rec.fAddr) { | |
| 77 SkDebugf("mmap failed\n"); | |
| 78 close(rec.fFD); | |
| 79 return NULL; | |
| 80 } | |
| 81 (void) ashmem_pin_region(rec.fFD, 0, 0); | |
| 82 #ifdef SK_DEBUG | |
| 83 rec.fPinned = true; | |
| 84 #endif | |
| 85 // In release mode, we do not keep a pointer to this object. It will be dest
royed | |
| 86 // either when pinCache returns NULL or when throwAwayCache is called. | |
| 87 AshmemRec* pRec = SkNEW_ARGS(AshmemRec, (rec)); | |
| 88 *ID = reinterpret_cast<intptr_t>(pRec); | |
| 89 #ifdef SK_DEBUG | |
| 90 this->appendRec(pRec); | |
| 91 #endif | |
| 92 return rec.fAddr; | |
| 93 } | |
| 94 | |
| 95 void* SkAshmemImageCache::pinCache(intptr_t ID) { | |
| 96 SkAutoMutexAcquire ac(&gAshmemMutex); | |
| 97 AshmemRec* rec = reinterpret_cast<AshmemRec*>(ID); | |
| 98 const int fd = rec->fFD; | |
| 99 int pin = ashmem_pin_region(fd, 0, 0); | |
| 100 if (ASHMEM_NOT_PURGED == pin) { | |
| 101 #ifdef SK_DEBUG | |
| 102 rec->fPinned = true; | |
| 103 #endif | |
| 104 return rec->fAddr; | |
| 105 } | |
| 106 ashmem_unpin_region(fd, 0, 0); | |
| 107 return NULL; | |
| 108 } | |
| 109 | |
| 110 void SkAshmemImageCache::releaseCache(intptr_t ID) { | |
| 111 SkAutoMutexAcquire ac(&gAshmemMutex); | |
| 112 AshmemRec* rec = reinterpret_cast<AshmemRec*>(ID); | |
| 113 ashmem_unpin_region(rec->fFD, 0, 0); | |
| 114 #ifdef SK_DEBUG | |
| 115 rec->fPinned = false; | |
| 116 #endif | |
| 117 } | |
| 118 | |
| 119 void SkAshmemImageCache::throwAwayCache(intptr_t ID) { | |
| 120 SkAutoMutexAcquire ac(&gAshmemMutex); | |
| 121 AshmemRec* rec = reinterpret_cast<AshmemRec*>(ID); | |
| 122 munmap(rec->fAddr, rec->fSize); | |
| 123 close(rec->fFD); | |
| 124 #ifdef SK_DEBUG | |
| 125 SkASSERT(!rec->fPinned); | |
| 126 int index = this->findRec(rec); | |
| 127 SkASSERT(index >= 0); | |
| 128 fRecs.remove(index); | |
| 129 #endif | |
| 130 SkDELETE(rec); | |
| 131 } | |
| 132 | |
| 133 #ifdef SK_DEBUG | |
| 134 void SkAshmemImageCache::appendRec(SkAshmemImageCache::AshmemRec* rec) { | |
| 135 int index = this->findRec(rec); | |
| 136 // Should not already exist. | |
| 137 SkASSERT(index < 0); | |
| 138 fRecs.insert(~index, 1, &rec); | |
| 139 } | |
| 140 | |
| 141 int SkAshmemImageCache::AshmemRec::Compare(const SkAshmemImageCache::AshmemRec*
a, | |
| 142 const SkAshmemImageCache::AshmemRec*
b) { | |
| 143 return reinterpret_cast<intptr_t>(a) - reinterpret_cast<intptr_t>(b); | |
| 144 } | |
| 145 | |
| 146 int SkAshmemImageCache::findRec(const SkAshmemImageCache::AshmemRec* rec) const
{ | |
| 147 return SkTSearch<AshmemRec>((const AshmemRec**)fRecs.begin(), fRecs.count(),
rec, | |
| 148 sizeof(intptr_t), AshmemRec::Compare); | |
| 149 } | |
| 150 | |
| 151 SkImageCache::CacheStatus SkAshmemImageCache::getCacheStatus(intptr_t ID) const
{ | |
| 152 SkAutoMutexAcquire ac(&gAshmemMutex); | |
| 153 AshmemRec* rec = reinterpret_cast<AshmemRec*>(ID); | |
| 154 int index = this->findRec(rec); | |
| 155 if (index < 0) { | |
| 156 return SkImageCache::kThrownAway_CacheStatus; | |
| 157 } | |
| 158 return rec->fPinned ? SkImageCache::kPinned_CacheStatus | |
| 159 : SkImageCache::kUnpinned_CacheStatus; | |
| 160 } | |
| 161 #endif | |
| OLD | NEW |