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); |
+} |