michael@0: /* michael@0: * Copyright 2013 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #include "SkPurgeableMemoryBlock.h" michael@0: michael@0: #include michael@0: michael@0: bool SkPurgeableMemoryBlock::IsSupported() { michael@0: return true; michael@0: } michael@0: michael@0: #ifdef SK_DEBUG michael@0: bool SkPurgeableMemoryBlock::PlatformSupportsPurgingAllUnpinnedBlocks() { michael@0: return true; michael@0: } michael@0: michael@0: bool SkPurgeableMemoryBlock::PurgeAllUnpinnedBlocks() { michael@0: // Unused. michael@0: int state = 0; michael@0: kern_return_t ret = vm_purgable_control(mach_task_self(), 0, VM_PURGABLE_PURGE_ALL, &state); michael@0: return ret == KERN_SUCCESS; michael@0: } michael@0: michael@0: bool SkPurgeableMemoryBlock::purge() { michael@0: return false; michael@0: } michael@0: #endif michael@0: michael@0: static size_t round_to_page_size(size_t size) { michael@0: const size_t mask = 4096 - 1; michael@0: return (size + mask) & ~mask; michael@0: } michael@0: michael@0: SkPurgeableMemoryBlock::SkPurgeableMemoryBlock(size_t size) michael@0: : fAddr(NULL) michael@0: , fSize(round_to_page_size(size)) michael@0: , fPinned(false) { michael@0: } michael@0: michael@0: SkPurgeableMemoryBlock::~SkPurgeableMemoryBlock() { michael@0: SkDEBUGCODE(kern_return_t ret =) vm_deallocate(mach_task_self(), michael@0: reinterpret_cast(fAddr), michael@0: static_cast(fSize)); michael@0: #ifdef SK_DEBUG michael@0: if (ret != KERN_SUCCESS) { michael@0: SkDebugf("SkPurgeableMemoryBlock destructor failed to deallocate.\n"); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: void* SkPurgeableMemoryBlock::pin(SkPurgeableMemoryBlock::PinResult* pinResult) { michael@0: SkASSERT(!fPinned); michael@0: SkASSERT(pinResult != NULL); michael@0: if (NULL == fAddr) { michael@0: vm_address_t addr = 0; michael@0: kern_return_t ret = vm_allocate(mach_task_self(), &addr, static_cast(fSize), michael@0: VM_FLAGS_PURGABLE | VM_FLAGS_ANYWHERE); michael@0: if (KERN_SUCCESS == ret) { michael@0: fAddr = reinterpret_cast(addr); michael@0: *pinResult = kUninitialized_PinResult; michael@0: fPinned = true; michael@0: } else { michael@0: fAddr = NULL; michael@0: } michael@0: } else { michael@0: int state = VM_PURGABLE_NONVOLATILE; michael@0: kern_return_t ret = vm_purgable_control(mach_task_self(), michael@0: reinterpret_cast(fAddr), michael@0: VM_PURGABLE_SET_STATE, &state); michael@0: if (ret != KERN_SUCCESS) { michael@0: fAddr = NULL; michael@0: fPinned = false; michael@0: return NULL; michael@0: } michael@0: michael@0: fPinned = true; michael@0: michael@0: if (state & VM_PURGABLE_EMPTY) { michael@0: *pinResult = kUninitialized_PinResult; michael@0: } else { michael@0: *pinResult = kRetained_PinResult; michael@0: } michael@0: } michael@0: return fAddr; michael@0: } michael@0: michael@0: void SkPurgeableMemoryBlock::unpin() { michael@0: SkASSERT(fPinned); michael@0: int state = VM_PURGABLE_VOLATILE | VM_VOLATILE_GROUP_DEFAULT; michael@0: SkDEBUGCODE(kern_return_t ret =) vm_purgable_control(mach_task_self(), michael@0: reinterpret_cast(fAddr), michael@0: VM_PURGABLE_SET_STATE, &state); michael@0: fPinned = false; michael@0: michael@0: #ifdef SK_DEBUG michael@0: if (ret != KERN_SUCCESS) { michael@0: SkDebugf("SkPurgeableMemoryBlock::unpin() failed.\n"); michael@0: } michael@0: #endif michael@0: }