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/scoped_ptr.h"
19 // The VM subsystem allows tagging of memory and 240-255 is reserved for
20 // application use (see mach/vm_statistics.h). Pick 252 (after chromium's atomic
22 const int kDiscardableMemoryTag = VM_MAKE_TAG(252);
24 class DiscardableMemoryMac : public DiscardableMemory {
26 explicit DiscardableMemoryMac(size_t size)
32 kern_return_t ret = vm_allocate(mach_task_self(),
37 kDiscardableMemoryTag);
38 if (ret != KERN_SUCCESS) {
39 DLOG(ERROR) << "vm_allocate() failed";
46 virtual ~DiscardableMemoryMac() {
48 vm_deallocate(mach_task_self(), buffer_, size_);
51 virtual DiscardableMemoryLockStatus Lock() OVERRIDE {
52 DCHECK_EQ(0, mprotect(reinterpret_cast<void*>(buffer_),
54 PROT_READ | PROT_WRITE));
55 int state = VM_PURGABLE_NONVOLATILE;
56 kern_return_t ret = vm_purgable_control(mach_task_self(),
58 VM_PURGABLE_SET_STATE,
60 if (ret != KERN_SUCCESS)
61 return DISCARDABLE_MEMORY_LOCK_STATUS_FAILED;
63 return state & VM_PURGABLE_EMPTY ? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED
64 : DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS;
67 virtual void Unlock() OVERRIDE {
68 int state = VM_PURGABLE_VOLATILE | VM_VOLATILE_GROUP_DEFAULT;
69 kern_return_t ret = vm_purgable_control(mach_task_self(),
71 VM_PURGABLE_SET_STATE,
73 DCHECK_EQ(0, mprotect(reinterpret_cast<void*>(buffer_), size_, PROT_NONE));
74 if (ret != KERN_SUCCESS)
75 DLOG(ERROR) << "Failed to unlock memory.";
78 virtual void* Memory() const OVERRIDE {
79 return reinterpret_cast<void*>(buffer_);
86 DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryMac);
92 void DiscardableMemory::RegisterMemoryPressureListeners() {
93 internal::DiscardableMemoryEmulated::RegisterMemoryPressureListeners();
97 void DiscardableMemory::UnregisterMemoryPressureListeners() {
98 internal::DiscardableMemoryEmulated::UnregisterMemoryPressureListeners();
102 void DiscardableMemory::GetSupportedTypes(
103 std::vector<DiscardableMemoryType>* types) {
104 const DiscardableMemoryType supported_types[] = {
105 DISCARDABLE_MEMORY_TYPE_MAC,
106 DISCARDABLE_MEMORY_TYPE_EMULATED
108 types->assign(supported_types, supported_types + arraysize(supported_types));
112 scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemoryWithType(
113 DiscardableMemoryType type, size_t size) {
115 case DISCARDABLE_MEMORY_TYPE_NONE:
116 case DISCARDABLE_MEMORY_TYPE_ANDROID:
117 return scoped_ptr<DiscardableMemory>();
118 case DISCARDABLE_MEMORY_TYPE_MAC: {
119 scoped_ptr<DiscardableMemoryMac> memory(new DiscardableMemoryMac(size));
120 if (!memory->Initialize())
121 return scoped_ptr<DiscardableMemory>();
123 return memory.PassAs<DiscardableMemory>();
125 case DISCARDABLE_MEMORY_TYPE_EMULATED: {
126 scoped_ptr<internal::DiscardableMemoryEmulated> memory(
127 new internal::DiscardableMemoryEmulated(size));
128 if (!memory->Initialize())
129 return scoped_ptr<DiscardableMemory>();
131 return memory.PassAs<DiscardableMemory>();
136 return scoped_ptr<DiscardableMemory>();
140 bool DiscardableMemory::PurgeForTestingSupported() {
145 void DiscardableMemory::PurgeForTesting() {
147 vm_purgable_control(mach_task_self(), 0, VM_PURGABLE_PURGE_ALL, &state);
148 internal::DiscardableMemoryEmulated::PurgeForTesting();