/* * 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 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(fAddr), static_cast(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(fSize), VM_FLAGS_PURGABLE | VM_FLAGS_ANYWHERE); if (KERN_SUCCESS == ret) { fAddr = reinterpret_cast(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(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(fAddr), VM_PURGABLE_SET_STATE, &state); fPinned = false; #ifdef SK_DEBUG if (ret != KERN_SUCCESS) { SkDebugf("SkPurgeableMemoryBlock::unpin() failed.\n"); } #endif }