• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
IsSupported()12 bool SkPurgeableMemoryBlock::IsSupported() {
13     return true;
14 }
15 
16 #ifdef SK_DEBUG
PlatformSupportsPurgingAllUnpinnedBlocks()17 bool SkPurgeableMemoryBlock::PlatformSupportsPurgingAllUnpinnedBlocks() {
18     return true;
19 }
20 
PurgeAllUnpinnedBlocks()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 
purge()28 bool SkPurgeableMemoryBlock::purge() {
29     return false;
30 }
31 #endif
32 
round_to_page_size(size_t size)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 
SkPurgeableMemoryBlock(size_t size)38 SkPurgeableMemoryBlock::SkPurgeableMemoryBlock(size_t size)
39     : fAddr(NULL)
40     , fSize(round_to_page_size(size))
41     , fPinned(false) {
42 }
43 
~SkPurgeableMemoryBlock()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 
pin(SkPurgeableMemoryBlock::PinResult * pinResult)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 
unpin()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