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
3 // found in the LICENSE file.
5 #include "base/memory/discardable_memory.h"
10 #include "base/basictypes.h"
11 #include "base/compiler_specific.h"
12 #include "base/logging.h"
13 #include "base/memory/discardable_memory_emulated.h"
14 #include "base/memory/discardable_memory_malloc.h"
15 #include "base/memory/scoped_ptr.h"
20 // The VM subsystem allows tagging of memory and 240-255 is reserved for
21 // application use (see mach/vm_statistics.h). Pick 252 (after chromium's atomic
23 const int kDiscardableMemoryTag
= VM_MAKE_TAG(252);
25 class DiscardableMemoryMac
: public DiscardableMemory
{
27 explicit DiscardableMemoryMac(size_t size
)
33 kern_return_t ret
= vm_allocate(mach_task_self(),
38 kDiscardableMemoryTag
);
39 if (ret
!= KERN_SUCCESS
) {
40 DLOG(ERROR
) << "vm_allocate() failed";
47 virtual ~DiscardableMemoryMac() {
49 vm_deallocate(mach_task_self(), buffer_
, size_
);
52 virtual DiscardableMemoryLockStatus
Lock() OVERRIDE
{
53 DCHECK_EQ(0, mprotect(reinterpret_cast<void*>(buffer_
),
55 PROT_READ
| PROT_WRITE
));
56 int state
= VM_PURGABLE_NONVOLATILE
;
57 kern_return_t ret
= vm_purgable_control(mach_task_self(),
59 VM_PURGABLE_SET_STATE
,
61 if (ret
!= KERN_SUCCESS
)
62 return DISCARDABLE_MEMORY_LOCK_STATUS_FAILED
;
64 return state
& VM_PURGABLE_EMPTY
? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED
65 : DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS
;
68 virtual void Unlock() OVERRIDE
{
69 int state
= VM_PURGABLE_VOLATILE
| VM_VOLATILE_GROUP_DEFAULT
;
70 kern_return_t ret
= vm_purgable_control(mach_task_self(),
72 VM_PURGABLE_SET_STATE
,
74 DCHECK_EQ(0, mprotect(reinterpret_cast<void*>(buffer_
), size_
, PROT_NONE
));
75 if (ret
!= KERN_SUCCESS
)
76 DLOG(ERROR
) << "Failed to unlock memory.";
79 virtual void* Memory() const OVERRIDE
{
80 return reinterpret_cast<void*>(buffer_
);
87 DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryMac
);
93 void DiscardableMemory::RegisterMemoryPressureListeners() {
94 internal::DiscardableMemoryEmulated::RegisterMemoryPressureListeners();
98 void DiscardableMemory::UnregisterMemoryPressureListeners() {
99 internal::DiscardableMemoryEmulated::UnregisterMemoryPressureListeners();
103 void DiscardableMemory::GetSupportedTypes(
104 std::vector
<DiscardableMemoryType
>* types
) {
105 const DiscardableMemoryType supported_types
[] = {
106 DISCARDABLE_MEMORY_TYPE_MAC
,
107 DISCARDABLE_MEMORY_TYPE_EMULATED
,
108 DISCARDABLE_MEMORY_TYPE_MALLOC
110 types
->assign(supported_types
, supported_types
+ arraysize(supported_types
));
114 scoped_ptr
<DiscardableMemory
> DiscardableMemory::CreateLockedMemoryWithType(
115 DiscardableMemoryType type
, size_t size
) {
117 case DISCARDABLE_MEMORY_TYPE_NONE
:
118 case DISCARDABLE_MEMORY_TYPE_ANDROID
:
119 return scoped_ptr
<DiscardableMemory
>();
120 case DISCARDABLE_MEMORY_TYPE_MAC
: {
121 scoped_ptr
<DiscardableMemoryMac
> memory(new DiscardableMemoryMac(size
));
122 if (!memory
->Initialize())
123 return scoped_ptr
<DiscardableMemory
>();
125 return memory
.PassAs
<DiscardableMemory
>();
127 case DISCARDABLE_MEMORY_TYPE_EMULATED
: {
128 scoped_ptr
<internal::DiscardableMemoryEmulated
> memory(
129 new internal::DiscardableMemoryEmulated(size
));
130 if (!memory
->Initialize())
131 return scoped_ptr
<DiscardableMemory
>();
133 return memory
.PassAs
<DiscardableMemory
>();
135 case DISCARDABLE_MEMORY_TYPE_MALLOC
: {
136 scoped_ptr
<internal::DiscardableMemoryMalloc
> memory(
137 new internal::DiscardableMemoryMalloc(size
));
138 if (!memory
->Initialize())
139 return scoped_ptr
<DiscardableMemory
>();
141 return memory
.PassAs
<DiscardableMemory
>();
146 return scoped_ptr
<DiscardableMemory
>();
150 bool DiscardableMemory::PurgeForTestingSupported() {
155 void DiscardableMemory::PurgeForTesting() {
157 vm_purgable_control(mach_task_self(), 0, VM_PURGABLE_PURGE_ALL
, &state
);
158 internal::DiscardableMemoryEmulated::PurgeForTesting();