Chromium Code Reviews| 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" | |
| 6 | |
| 7 #include <mach/mach.h> | 5 #include <mach/mach.h> |
| 8 #include <sys/mman.h> | 6 #include <sys/mman.h> |
| 9 | 7 |
| 10 #include "base/basictypes.h" | 8 #include "base/basictypes.h" |
| 11 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
| 10 #include "base/lazy_instance.h" | |
| 12 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/memory/discardable_memory.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() { | |
|
Philippe
2013/12/17 14:28:21
Are you making this change for consistency with th
reveman
2013/12/18 08:12:38
This is for consistency. I might also move this im
| |
| 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 LockDiscardableMemoryStatus 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_PURGED |
| 49 : DISCARDABLE_MEMORY_SUCCESS; | 62 : DISCARDABLE_MEMORY_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 |
| 87 struct SupportedTypeVector { | |
| 88 SupportedTypeVector() { | |
| 89 v.push_back(DISCARDABLE_MEMORY_MAC); | |
| 90 v.push_back(DISCARDABLE_MEMORY_EMULATED); | |
| 91 } | |
| 92 std::vector<DiscardableMemoryType> v; | |
| 93 }; | |
| 94 LazyInstance<SupportedTypeVector>::Leaky g_supported_types = | |
| 95 LAZY_INSTANCE_INITIALIZER; | |
| 96 | |
| 75 } // namespace | 97 } // namespace |
| 76 | 98 |
| 77 // static | 99 // static |
| 78 bool DiscardableMemory::SupportedNatively() { | 100 const std::vector<DiscardableMemoryType>& |
| 79 return true; | 101 DiscardableMemory::GetSupportedTypes() { |
| 102 return g_supported_types.Get().v; | |
| 80 } | 103 } |
| 81 | 104 |
| 82 // static | 105 // static |
| 83 scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemory( | 106 scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemory( |
| 84 size_t size) { | 107 size_t size) { |
| 85 vm_address_t buffer = 0; | 108 switch (GetType()) { |
| 86 kern_return_t ret = vm_allocate(mach_task_self(), | 109 case DISCARDABLE_MEMORY_NONE: |
| 87 &buffer, | 110 case DISCARDABLE_MEMORY_ANDROID: |
| 88 size, | 111 return scoped_ptr<DiscardableMemory>(); |
| 89 VM_FLAGS_PURGABLE | | 112 case DISCARDABLE_MEMORY_MAC: { |
| 90 VM_FLAGS_ANYWHERE | | 113 scoped_ptr<DiscardableMemoryMac> memory(new DiscardableMemoryMac(size)); |
| 91 kDiscardableMemoryTag); | 114 if (!memory->Initialize()) |
| 92 if (ret != KERN_SUCCESS) { | 115 return scoped_ptr<DiscardableMemory>(); |
| 93 DLOG(ERROR) << "vm_allocate() failed"; | 116 |
| 94 return scoped_ptr<DiscardableMemory>(); | 117 return memory.PassAs<DiscardableMemory>(); |
| 118 } | |
| 119 case DISCARDABLE_MEMORY_EMULATED: { | |
| 120 scoped_ptr<internal::DiscardableMemoryEmulated> memory( | |
| 121 new internal::DiscardableMemoryEmulated(size)); | |
| 122 if (!memory->Initialize()) | |
| 123 return scoped_ptr<DiscardableMemory>(); | |
| 124 | |
| 125 return memory.PassAs<DiscardableMemory>(); | |
| 126 } | |
| 95 } | 127 } |
| 96 return scoped_ptr<DiscardableMemory>( | 128 |
| 97 new DiscardableMemoryMac(reinterpret_cast<void*>(buffer), size)); | 129 NOTREACHED(); |
| 130 return scoped_ptr<DiscardableMemory>(); | |
| 98 } | 131 } |
| 99 | 132 |
| 100 // static | 133 // static |
| 101 bool DiscardableMemory::PurgeForTestingSupported() { | 134 bool DiscardableMemory::PurgeForTestingSupported() { |
| 102 return true; | 135 return true; |
| 103 } | 136 } |
| 104 | 137 |
| 105 // static | 138 // static |
| 106 void DiscardableMemory::PurgeForTesting() { | 139 void DiscardableMemory::PurgeForTesting() { |
| 107 int state = 0; | 140 int state = 0; |
| 108 vm_purgable_control(mach_task_self(), 0, VM_PURGABLE_PURGE_ALL, &state); | 141 vm_purgable_control(mach_task_self(), 0, VM_PURGABLE_PURGE_ALL, &state); |
| 142 internal::DiscardableMemoryEmulated::PurgeForTesting(); | |
| 109 } | 143 } |
| 110 | 144 |
| 111 } // namespace base | 145 } // namespace base |
| OLD | NEW |