OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/memory/discardable_memory.h" | 5 #include "base/memory/discardable_memory.h" |
6 | 6 |
7 #include <mach/mach.h> | 7 #include <mach/mach.h> |
8 #include <sys/mman.h> | 8 #include <sys/mman.h> |
9 | 9 |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
11 #include "base/compiler_specific.h" | 11 #include "base/compiler_specific.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/memory/discardable_memory_emulated.h" |
13 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
14 | 15 |
15 namespace base { | 16 namespace base { |
16 namespace { | 17 namespace { |
17 | 18 |
18 // The VM subsystem allows tagging of memory and 240-255 is reserved for | 19 // The VM subsystem allows tagging of memory and 240-255 is reserved for |
19 // application use (see mach/vm_statistics.h). Pick 252 (after chromium's atomic | 20 // application use (see mach/vm_statistics.h). Pick 252 (after chromium's atomic |
20 // weight of ~52). | 21 // weight of ~52). |
21 const int kDiscardableMemoryTag = VM_MAKE_TAG(252); | 22 const int kDiscardableMemoryTag = VM_MAKE_TAG(252); |
22 | 23 |
23 class DiscardableMemoryMac : public DiscardableMemory { | 24 class DiscardableMemoryMac : public DiscardableMemory { |
24 public: | 25 public: |
25 DiscardableMemoryMac(void* memory, size_t size) | 26 explicit DiscardableMemoryMac(size_t size) |
26 : memory_(memory), | 27 : buffer_(0), |
27 size_(size) { | 28 size_(size) { |
28 DCHECK(memory_); | 29 } |
| 30 |
| 31 bool Initialize() { |
| 32 kern_return_t ret = vm_allocate(mach_task_self(), |
| 33 &buffer_, |
| 34 size_, |
| 35 VM_FLAGS_PURGABLE | |
| 36 VM_FLAGS_ANYWHERE | |
| 37 kDiscardableMemoryTag); |
| 38 if (ret != KERN_SUCCESS) { |
| 39 DLOG(ERROR) << "vm_allocate() failed"; |
| 40 return false; |
| 41 } |
| 42 |
| 43 return true; |
29 } | 44 } |
30 | 45 |
31 virtual ~DiscardableMemoryMac() { | 46 virtual ~DiscardableMemoryMac() { |
32 vm_deallocate(mach_task_self(), | 47 if (buffer_) |
33 reinterpret_cast<vm_address_t>(memory_), | 48 vm_deallocate(mach_task_self(), buffer_, size_); |
34 size_); | |
35 } | 49 } |
36 | 50 |
37 virtual LockDiscardableMemoryStatus Lock() OVERRIDE { | 51 virtual DiscardableMemoryLockStatus Lock() OVERRIDE { |
38 DCHECK_EQ(0, mprotect(memory_, size_, PROT_READ | PROT_WRITE)); | 52 DCHECK_EQ(0, mprotect(buffer_, size_, PROT_READ | PROT_WRITE)); |
39 int state = VM_PURGABLE_NONVOLATILE; | 53 int state = VM_PURGABLE_NONVOLATILE; |
40 kern_return_t ret = vm_purgable_control( | 54 kern_return_t ret = vm_purgable_control(mach_task_self(), |
41 mach_task_self(), | 55 buffer_, |
42 reinterpret_cast<vm_address_t>(memory_), | 56 VM_PURGABLE_SET_STATE, |
43 VM_PURGABLE_SET_STATE, | 57 &state); |
44 &state); | |
45 if (ret != KERN_SUCCESS) | 58 if (ret != KERN_SUCCESS) |
46 return DISCARDABLE_MEMORY_FAILED; | 59 return DISCARDABLE_MEMORY_FAILED; |
47 | 60 |
48 return state & VM_PURGABLE_EMPTY ? DISCARDABLE_MEMORY_PURGED | 61 return state & VM_PURGABLE_EMPTY ? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED |
49 : DISCARDABLE_MEMORY_SUCCESS; | 62 : DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS; |
50 } | 63 } |
51 | 64 |
52 virtual void Unlock() OVERRIDE { | 65 virtual void Unlock() OVERRIDE { |
53 int state = VM_PURGABLE_VOLATILE | VM_VOLATILE_GROUP_DEFAULT; | 66 int state = VM_PURGABLE_VOLATILE | VM_VOLATILE_GROUP_DEFAULT; |
54 kern_return_t ret = vm_purgable_control( | 67 kern_return_t ret = vm_purgable_control(mach_task_self(), |
55 mach_task_self(), | 68 buffer_, |
56 reinterpret_cast<vm_address_t>(memory_), | 69 VM_PURGABLE_SET_STATE, |
57 VM_PURGABLE_SET_STATE, | 70 &state); |
58 &state); | 71 DCHECK_EQ(0, mprotect(buffer_, size_, PROT_NONE)); |
59 DCHECK_EQ(0, mprotect(memory_, size_, PROT_NONE)); | |
60 if (ret != KERN_SUCCESS) | 72 if (ret != KERN_SUCCESS) |
61 DLOG(ERROR) << "Failed to unlock memory."; | 73 DLOG(ERROR) << "Failed to unlock memory."; |
62 } | 74 } |
63 | 75 |
64 virtual void* Memory() const OVERRIDE { | 76 virtual void* Memory() const OVERRIDE { |
65 return memory_; | 77 return buffer_; |
66 } | 78 } |
67 | 79 |
68 private: | 80 private: |
69 void* const memory_; | 81 vm_address_t buffer_; |
70 const size_t size_; | 82 const size_t size_; |
71 | 83 |
72 DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryMac); | 84 DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryMac); |
73 }; | 85 }; |
74 | 86 |
75 } // namespace | 87 } // namespace |
76 | 88 |
77 // static | 89 // static |
78 bool DiscardableMemory::SupportedNatively() { | 90 void DiscardableMemory::GetSupportedTypes( |
79 return true; | 91 std::vector<DiscardableMemoryType>* types) { |
| 92 const DiscardableMemoryType supported_types[] = { |
| 93 DISCARDABLE_MEMORY_TYPE_MAC, |
| 94 DISCARDABLE_MEMORY_TYPE_EMULATED |
| 95 }; |
| 96 types->assign(supported_types, supported_types + arraysize(supported_types)); |
80 } | 97 } |
81 | 98 |
82 // static | 99 // static |
83 scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemory( | 100 scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemory( |
84 size_t size) { | 101 DiscardableMemoryType type, size_t size) { |
85 vm_address_t buffer = 0; | 102 switch (type) { |
86 kern_return_t ret = vm_allocate(mach_task_self(), | 103 case DISCARDABLE_MEMORY_TYPE_NONE: |
87 &buffer, | 104 case DISCARDABLE_MEMORY_TYPE_ANDROID: |
88 size, | 105 return scoped_ptr<DiscardableMemory>(); |
89 VM_FLAGS_PURGABLE | | 106 case DISCARDABLE_MEMORY_TYPE_MAC: { |
90 VM_FLAGS_ANYWHERE | | 107 scoped_ptr<DiscardableMemoryMac> memory(new DiscardableMemoryMac(size)); |
91 kDiscardableMemoryTag); | 108 if (!memory->Initialize()) |
92 if (ret != KERN_SUCCESS) { | 109 return scoped_ptr<DiscardableMemory>(); |
93 DLOG(ERROR) << "vm_allocate() failed"; | 110 |
94 return scoped_ptr<DiscardableMemory>(); | 111 return memory.PassAs<DiscardableMemory>(); |
| 112 } |
| 113 case DISCARDABLE_MEMORY_TYPE_EMULATED: { |
| 114 scoped_ptr<internal::DiscardableMemoryEmulated> memory( |
| 115 new internal::DiscardableMemoryEmulated(size)); |
| 116 if (!memory->Initialize()) |
| 117 return scoped_ptr<DiscardableMemory>(); |
| 118 |
| 119 return memory.PassAs<DiscardableMemory>(); |
| 120 } |
95 } | 121 } |
96 return scoped_ptr<DiscardableMemory>( | 122 |
97 new DiscardableMemoryMac(reinterpret_cast<void*>(buffer), size)); | 123 NOTREACHED(); |
| 124 return scoped_ptr<DiscardableMemory>(); |
98 } | 125 } |
99 | 126 |
100 // static | 127 // static |
101 bool DiscardableMemory::PurgeForTestingSupported() { | 128 bool DiscardableMemory::PurgeForTestingSupported() { |
102 return true; | 129 return true; |
103 } | 130 } |
104 | 131 |
105 // static | 132 // static |
106 void DiscardableMemory::PurgeForTesting() { | 133 void DiscardableMemory::PurgeForTesting() { |
107 int state = 0; | 134 int state = 0; |
108 vm_purgable_control(mach_task_self(), 0, VM_PURGABLE_PURGE_ALL, &state); | 135 vm_purgable_control(mach_task_self(), 0, VM_PURGABLE_PURGE_ALL, &state); |
| 136 internal::DiscardableMemoryEmulated::PurgeForTesting(); |
109 } | 137 } |
110 | 138 |
111 } // namespace base | 139 } // namespace base |
OLD | NEW |