Add a string for translation.
[chromium-blink-merge.git] / base / memory / discardable_memory_mac.cc
blob40a97392e955e1a740171f82ffca6f9508fa3805
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"
7 #include <mach/mach.h>
8 #include <sys/mman.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"
17 namespace base {
18 namespace {
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
22 // weight of ~52).
23 const int kDiscardableMemoryTag = VM_MAKE_TAG(252);
25 class DiscardableMemoryMac : public DiscardableMemory {
26 public:
27 explicit DiscardableMemoryMac(size_t size)
28 : buffer_(0),
29 size_(size) {
32 bool Initialize() {
33 kern_return_t ret = vm_allocate(mach_task_self(),
34 &buffer_,
35 size_,
36 VM_FLAGS_PURGABLE |
37 VM_FLAGS_ANYWHERE |
38 kDiscardableMemoryTag);
39 if (ret != KERN_SUCCESS) {
40 DLOG(ERROR) << "vm_allocate() failed";
41 return false;
44 return true;
47 virtual ~DiscardableMemoryMac() {
48 if (buffer_)
49 vm_deallocate(mach_task_self(), buffer_, size_);
52 virtual DiscardableMemoryLockStatus Lock() OVERRIDE {
53 DCHECK_EQ(0, mprotect(reinterpret_cast<void*>(buffer_),
54 size_,
55 PROT_READ | PROT_WRITE));
56 int state = VM_PURGABLE_NONVOLATILE;
57 kern_return_t ret = vm_purgable_control(mach_task_self(),
58 buffer_,
59 VM_PURGABLE_SET_STATE,
60 &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(),
71 buffer_,
72 VM_PURGABLE_SET_STATE,
73 &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_);
83 private:
84 vm_address_t buffer_;
85 const size_t size_;
87 DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryMac);
90 } // namespace
92 // static
93 void DiscardableMemory::RegisterMemoryPressureListeners() {
94 internal::DiscardableMemoryEmulated::RegisterMemoryPressureListeners();
97 // static
98 void DiscardableMemory::UnregisterMemoryPressureListeners() {
99 internal::DiscardableMemoryEmulated::UnregisterMemoryPressureListeners();
102 // static
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));
113 // static
114 scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemoryWithType(
115 DiscardableMemoryType type, size_t size) {
116 switch (type) {
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>();
145 NOTREACHED();
146 return scoped_ptr<DiscardableMemory>();
149 // static
150 bool DiscardableMemory::PurgeForTestingSupported() {
151 return true;
154 // static
155 void DiscardableMemory::PurgeForTesting() {
156 int state = 0;
157 vm_purgable_control(mach_task_self(), 0, VM_PURGABLE_PURGE_ALL, &state);
158 internal::DiscardableMemoryEmulated::PurgeForTesting();
161 } // namespace base