| /* |
| * 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 |
| } |