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