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 12bool SkPurgeableMemoryBlock::IsSupported() { 13 return true; 14} 15 16#ifdef SK_DEBUG 17bool SkPurgeableMemoryBlock::PlatformSupportsPurgingAllUnpinnedBlocks() { 18 return true; 19} 20 21bool 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 28bool SkPurgeableMemoryBlock::purge() { 29 return false; 30} 31#endif 32 33static size_t round_to_page_size(size_t size) { 34 const size_t mask = 4096 - 1; 35 return (size + mask) & ~mask; 36} 37 38SkPurgeableMemoryBlock::SkPurgeableMemoryBlock(size_t size) 39 : fAddr(NULL) 40 , fSize(round_to_page_size(size)) 41 , fPinned(false) { 42} 43 44SkPurgeableMemoryBlock::~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 55void* 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 91void 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