Home | History | Annotate | Download | only in ports
      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