| Index: src/ports/SkMacImageCache.cpp
|
| diff --git a/src/ports/SkMacImageCache.cpp b/src/ports/SkMacImageCache.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..51c263209c894b52ee97eee33b02a96d156dd493
|
| --- /dev/null
|
| +++ b/src/ports/SkMacImageCache.cpp
|
| @@ -0,0 +1,171 @@
|
| +/*
|
| + * Copyright 2013 Google Inc.
|
| + *
|
| + * Use of this source code is governed by a BSD-style license that can be
|
| + * found in the LICENSE file.
|
| + */
|
| +
|
| +#include "SkMacImageCache.h"
|
| +#include "SkThread.h"
|
| +
|
| +#ifdef SK_DEBUG
|
| + #include "SkTSearch.h"
|
| +#endif
|
| +
|
| +SK_DECLARE_STATIC_MUTEX(gMacImageMutex);
|
| +
|
| +SkMacImageCache* SkMacImageCache::GetMacImageCache() {
|
| + SkAutoMutexAcquire ac(&gMacImageMutex);
|
| + static SkMacImageCache gCache;
|
| + return &gCache;
|
| +}
|
| +
|
| +SkMacImageCache::SkMacImageCache() {}
|
| +
|
| +#ifdef SK_DEBUG
|
| +SkMacImageCache::~SkMacImageCache() {
|
| + SkASSERT(fRecs.count() == 0);
|
| +}
|
| +#endif
|
| +
|
| +static size_t round_to_page_size(size_t size) {
|
| + const size_t mask = 4096 - 1;
|
| + return (size + mask) & ~mask;
|
| +}
|
| +
|
| +void* SkMacImageCache::allocAndPinCache(size_t bytes, intptr_t* ID) {
|
| + SkAutoMutexAcquire ac(&gMacImageMutex);
|
| + Rec rec;
|
| + rec.fAddr = 0;
|
| + rec.fSize = round_to_page_size(bytes);
|
| + kern_return_t ret = vm_allocate(mach_task_self(), &rec.fAddr, rec.fSize,
|
| + VM_FLAGS_PURGABLE | VM_FLAGS_ANYWHERE);
|
| + if (ret != KERN_SUCCESS) {
|
| + SkDebugf("SkMacImageCache::allocAndPinCache failed to allocate.\n");
|
| + return NULL;
|
| + }
|
| +
|
| + Rec* pRec = SkNEW_ARGS(Rec, (rec));
|
| + SkASSERT(ID != NULL);
|
| + *ID = reinterpret_cast<intptr_t>(pRec);
|
| +#ifdef SK_DEBUG
|
| + pRec->fPinned = true;
|
| + // Insert into the array of all recs:
|
| + int index = this->findRec(*ID);
|
| + SkASSERT(index < 0);
|
| + fRecs.insert(~index, 1, ID);
|
| +#endif
|
| + return reinterpret_cast<void*>(pRec->fAddr);
|
| +}
|
| +
|
| +void* SkMacImageCache::pinCache(intptr_t ID, SkImageCache::PurgeStatus* status) {
|
| + SkASSERT(ID != SkImageCache::UNINITIALIZED_ID);
|
| + SkAutoMutexAcquire ac(&gMacImageMutex);
|
| + Rec* rec = reinterpret_cast<Rec*>(ID);
|
| +#ifdef SK_DEBUG
|
| + SkASSERT(!rec->fPinned);
|
| +#endif
|
| + int state = VM_PURGABLE_NONVOLATILE;
|
| + kern_return_t ret = vm_purgable_control(mach_task_self(), rec->fAddr, VM_PURGABLE_SET_STATE,
|
| + &state);
|
| + if (ret != KERN_SUCCESS) {
|
| + // Could not pin the memory, so deallocate it. The caller will need to reallocate.
|
| + ret = vm_deallocate(mach_task_self(), rec->fAddr, rec->fSize);
|
| + if (ret != KERN_SUCCESS) {
|
| + SkDebugf("SkMacImageCache::pinCache failed to deallocate.\n");
|
| + }
|
| + this->removeRec(ID);
|
| + return NULL;
|
| + }
|
| + SkASSERT(status != NULL);
|
| +#ifdef SK_DEBUG
|
| + rec->fPinned = true;
|
| +#endif
|
| + if (state & VM_PURGABLE_EMPTY) {
|
| + *status = SkImageCache::kPurged_PurgeStatus;
|
| + } else {
|
| + *status = SkImageCache::kNotPurged_PurgeStatus;
|
| + }
|
| + return reinterpret_cast<void*>(rec->fAddr);
|
| +}
|
| +
|
| +void SkMacImageCache::releaseCache(intptr_t ID) {
|
| + if (SkImageCache::UNINITIALIZED_ID == ID) {
|
| + return;
|
| + }
|
| + SkAutoMutexAcquire ac(&gMacImageMutex);
|
| + Rec* rec = reinterpret_cast<Rec*>(ID);
|
| + int state = VM_PURGABLE_VOLATILE | VM_VOLATILE_GROUP_DEFAULT;
|
| + kern_return_t ret = vm_purgable_control(mach_task_self(), rec->fAddr, VM_PURGABLE_SET_STATE,
|
| + &state);
|
| + if (ret != KERN_SUCCESS) {
|
| + SkDebugf("SkMacImageCache::releaseCache failed to unlock memory.\n");
|
| + }
|
| +#ifdef SK_DEBUG
|
| + SkASSERT(rec->fPinned);
|
| + rec->fPinned = false;
|
| +#endif
|
| +}
|
| +
|
| +void SkMacImageCache::throwAwayCache(intptr_t ID) {
|
| + if (SkImageCache::UNINITIALIZED_ID == ID) {
|
| + return;
|
| + }
|
| + SkAutoMutexAcquire ac(&gMacImageMutex);
|
| + Rec* rec = reinterpret_cast<Rec*>(ID);
|
| + SkASSERT(!rec->fPinned);
|
| + kern_return_t ret = vm_deallocate(mach_task_self(), rec->fAddr, rec->fSize);
|
| + if (ret != KERN_SUCCESS) {
|
| + SkDebugf("SkMacImageCache::throwAwayCache failed to deallocate.\n");
|
| + }
|
| + this->removeRec(ID);
|
| +}
|
| +
|
| +#ifdef SK_DEBUG
|
| +SkImageCache::PinStatus SkMacImageCache::getPinStatus(intptr_t ID) const {
|
| + SkAutoMutexAcquire ac(&gMacImageMutex);
|
| + if (SkImageCache::UNINITIALIZED_ID == ID || this->findRec(ID) < 0) {
|
| + return SkImageCache::kThrownAway_PinStatus;
|
| + }
|
| +
|
| + Rec* rec = reinterpret_cast<Rec*>(ID);
|
| + int state = 0;
|
| + kern_return_t ret = vm_purgable_control(mach_task_self(), rec->fAddr, VM_PURGABLE_GET_STATE,
|
| + &state);
|
| + if (ret != KERN_SUCCESS) {
|
| + return SkImageCache::kThrownAway_PinStatus;
|
| + }
|
| +
|
| + if (VM_PURGABLE_NONVOLATILE == state) {
|
| + SkASSERT(rec->fPinned);
|
| + return SkImageCache::kPinned_PinStatus;
|
| + }
|
| +
|
| + SkASSERT(!rec->fPinned);
|
| + return SkImageCache::kNeedsPin_PinStatus;
|
| +}
|
| +
|
| +void SkMacImageCache::purgeAllCaches() {
|
| + SkAutoMutexAcquire ac(&gMacImageMutex);
|
| + int state = 0;
|
| + kern_return_t ret = vm_purgable_control(mach_task_self(), 0, VM_PURGABLE_PURGE_ALL, &state);
|
| + if (ret != KERN_SUCCESS) {
|
| + SkDebugf("SkMacImageCache::purgeAllCaches failed to purge.\n");
|
| + }
|
| +}
|
| +
|
| +int SkMacImageCache::findRec(intptr_t rec) const {
|
| + return SkTSearch(fRecs.begin(), fRecs.count(), rec, sizeof(intptr_t));
|
| +}
|
| +#endif
|
| +
|
| +void SkMacImageCache::removeRec(intptr_t ID) {
|
| +#ifdef SK_DEBUG
|
| + int index = this->findRec(ID);
|
| + SkASSERT(index >= 0);
|
| + fRecs.remove(index);
|
| +#endif
|
| + Rec* rec = reinterpret_cast<Rec*>(ID);
|
| + SkASSERT(!rec->fPinned);
|
| + SkDELETE(rec);
|
| +}
|
|
|