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 "SkPurgeableMemoryBlock.h" 9 10 #include <mach/mach.h> 11 12 bool SkPurgeableMemoryBlock::IsSupported() { 13 return true; 14 } 15 16 #ifdef SK_DEBUG 17 bool SkPurgeableMemoryBlock::PlatformSupportsPurgingAllUnpinnedBlocks() { 18 return true; 19 } 20 21 bool SkPurgeableMemoryBlock::PurgeAllUnpinnedBlocks() { 22 // Unused. 23 int state = 0; 24 kern_return_t ret = vm_purgable_control(mach_task_self(), 0, VM_PURGABLE_PURGE_ALL, &state); 25 return ret == KERN_SUCCESS; 26 } 27 28 bool SkPurgeableMemoryBlock::purge() { 29 return false; 30 } 31 #endif 32 33 static size_t round_to_page_size(size_t size) { 34 const size_t mask = 4096 - 1; 35 return (size + mask) & ~mask; 36 } 37 38 SkPurgeableMemoryBlock::SkPurgeableMemoryBlock(size_t size) 39 : fAddr(NULL) 40 , fSize(round_to_page_size(size)) 41 , fPinned(false) { 42 } 43 44 SkPurgeableMemoryBlock::~SkPurgeableMemoryBlock() { 45 SkDEBUGCODE(kern_return_t ret =) vm_deallocate(mach_task_self(), 46 reinterpret_cast<vm_address_t>(fAddr), 47 static_cast<vm_size_t>(fSize)); 48 #ifdef SK_DEBUG 49 if (ret != KERN_SUCCESS) { 50 SkDebugf("SkPurgeableMemoryBlock destructor failed to deallocate.\n"); 51 } 52 #endif 53 } 54 55 void* SkPurgeableMemoryBlock::pin(SkPurgeableMemoryBlock::PinResult* pinResult) { 56 SkASSERT(!fPinned); 57 SkASSERT(pinResult != NULL); 58 if (NULL == fAddr) { 59 vm_address_t addr = 0; 60 kern_return_t ret = vm_allocate(mach_task_self(), &addr, static_cast<vm_size_t>(fSize), 61 VM_FLAGS_PURGABLE | VM_FLAGS_ANYWHERE); 62 if (KERN_SUCCESS == ret) { 63 fAddr = reinterpret_cast<void*>(addr); 64 *pinResult = kUninitialized_PinResult; 65 fPinned = true; 66 } else { 67 fAddr = NULL; 68 } 69 } else { 70 int state = VM_PURGABLE_NONVOLATILE; 71 kern_return_t ret = vm_purgable_control(mach_task_self(), 72 reinterpret_cast<vm_address_t>(fAddr), 73 VM_PURGABLE_SET_STATE, &state); 74 if (ret != KERN_SUCCESS) { 75 fAddr = NULL; 76 fPinned = false; 77 return NULL; 78 } 79 80 fPinned = true; 81 82 if (state & VM_PURGABLE_EMPTY) { 83 *pinResult = kUninitialized_PinResult; 84 } else { 85 *pinResult = kRetained_PinResult; 86 } 87 } 88 return fAddr; 89 } 90 91 void SkPurgeableMemoryBlock::unpin() { 92 SkASSERT(fPinned); 93 int state = VM_PURGABLE_VOLATILE | VM_VOLATILE_GROUP_DEFAULT; 94 SkDEBUGCODE(kern_return_t ret =) vm_purgable_control(mach_task_self(), 95 reinterpret_cast<vm_address_t>(fAddr), 96 VM_PURGABLE_SET_STATE, &state); 97 fPinned = false; 98 99 #ifdef SK_DEBUG 100 if (ret != KERN_SUCCESS) { 101 SkDebugf("SkPurgeableMemoryBlock::unpin() failed.\n"); 102 } 103 #endif 104 } 105