Index: src/ports/SkPurgeableMemoryBlock_mac.cpp |
diff --git a/src/ports/SkPurgeableMemoryBlock_mac.cpp b/src/ports/SkPurgeableMemoryBlock_mac.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5c44895fc3ca4fe1921df42e007db2ccb6479945 |
--- /dev/null |
+++ b/src/ports/SkPurgeableMemoryBlock_mac.cpp |
@@ -0,0 +1,105 @@ |
+/* |
+ * 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 "SkPurgeableMemoryBlock.h" |
+ |
+#include <mach/mach.h> |
+ |
+bool SkPurgeableMemoryBlock::IsSupported() { |
+ return true; |
+} |
+ |
+#ifdef SK_DEBUG |
+bool SkPurgeableMemoryBlock::PlatformSupportsPurgingAllUnpinnedBlocks() { |
+ return true; |
+} |
+ |
+bool SkPurgeableMemoryBlock::PurgeAllUnpinnedBlocks() { |
+ // Unused. |
+ int state = 0; |
+ kern_return_t ret = vm_purgable_control(mach_task_self(), 0, VM_PURGABLE_PURGE_ALL, &state); |
+ return ret == KERN_SUCCESS; |
+} |
+ |
+bool SkPurgeableMemoryBlock::purge() { |
+ return false; |
+} |
+#endif |
+ |
+static size_t round_to_page_size(size_t size) { |
+ const size_t mask = 4096 - 1; |
+ return (size + mask) & ~mask; |
+} |
+ |
+SkPurgeableMemoryBlock::SkPurgeableMemoryBlock(size_t size) |
+ : fAddr(NULL) |
+ , fSize(round_to_page_size(size)) |
+ , fPinned(false) { |
+} |
+ |
+SkPurgeableMemoryBlock::~SkPurgeableMemoryBlock() { |
+ SkDEBUGCODE(kern_return_t ret =) vm_deallocate(mach_task_self(), |
+ reinterpret_cast<vm_address_t>(fAddr), |
+ static_cast<vm_size_t>(fSize)); |
+#ifdef SK_DEBUG |
+ if (ret != KERN_SUCCESS) { |
+ SkDebugf("SkPurgeableMemoryBlock destructor failed to deallocate.\n"); |
+ } |
+#endif |
+} |
+ |
+void* SkPurgeableMemoryBlock::pin(SkPurgeableMemoryBlock::PinResult* pinResult) { |
+ SkASSERT(!fPinned); |
+ SkASSERT(pinResult != NULL); |
+ if (NULL == fAddr) { |
+ vm_address_t addr = 0; |
+ kern_return_t ret = vm_allocate(mach_task_self(), &addr, static_cast<vm_size_t>(fSize), |
+ VM_FLAGS_PURGABLE | VM_FLAGS_ANYWHERE); |
+ if (KERN_SUCCESS == ret) { |
+ fAddr = reinterpret_cast<void*>(addr); |
+ *pinResult = kUninitialized_PinResult; |
+ fPinned = true; |
+ } else { |
+ fAddr = NULL; |
+ } |
+ } else { |
+ int state = VM_PURGABLE_NONVOLATILE; |
+ kern_return_t ret = vm_purgable_control(mach_task_self(), |
+ reinterpret_cast<vm_address_t>(fAddr), |
+ VM_PURGABLE_SET_STATE, &state); |
+ if (ret != KERN_SUCCESS) { |
+ fAddr = NULL; |
+ fPinned = false; |
+ return NULL; |
+ } |
+ |
+ fPinned = true; |
+ |
+ if (state & VM_PURGABLE_EMPTY) { |
+ *pinResult = kUninitialized_PinResult; |
+ } else { |
+ *pinResult = kRetained_PinResult; |
+ } |
+ } |
+ return fAddr; |
+} |
+ |
+void SkPurgeableMemoryBlock::unpin() { |
+ SkASSERT(fPinned); |
+ int state = VM_PURGABLE_VOLATILE | VM_VOLATILE_GROUP_DEFAULT; |
+ SkDEBUGCODE(kern_return_t ret =) vm_purgable_control(mach_task_self(), |
+ reinterpret_cast<vm_address_t>(fAddr), |
+ VM_PURGABLE_SET_STATE, &state); |
+ fPinned = false; |
+ |
+#ifdef SK_DEBUG |
+ if (ret != KERN_SUCCESS) { |
+ SkDebugf("SkPurgeableMemoryBlock::unpin() failed.\n"); |
+ } |
+#endif |
+} |
+ |