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. 4 5 #include "base/memory/discardable_memory.h" 6 7 #include <mach/mach.h> 8 9 #include "base/logging.h" 10 11 namespace base { 12 13 namespace { 14 15 // The VM subsystem allows tagging of memory and 240-255 is reserved for 16 // application use (see mach/vm_statistics.h). Pick 252 (after chromium's atomic 17 // weight of ~52). 18 const int kDiscardableMemoryTag = VM_MAKE_TAG(252); 19 20 } // namespace 21 22 // static 23 bool DiscardableMemory::Supported() { 24 return true; 25 } 26 27 DiscardableMemory::~DiscardableMemory() { 28 if (memory_) { 29 vm_deallocate(mach_task_self(), 30 reinterpret_cast<vm_address_t>(memory_), 31 size_); 32 } 33 } 34 35 bool DiscardableMemory::InitializeAndLock(size_t size) { 36 DCHECK(!memory_); 37 size_ = size; 38 39 vm_address_t buffer = 0; 40 kern_return_t ret = vm_allocate(mach_task_self(), 41 &buffer, 42 size, 43 VM_FLAGS_PURGABLE | 44 VM_FLAGS_ANYWHERE | 45 kDiscardableMemoryTag); 46 47 if (ret != KERN_SUCCESS) { 48 DLOG(ERROR) << "vm_allocate() failed"; 49 return false; 50 } 51 52 is_locked_ = true; 53 memory_ = reinterpret_cast<void*>(buffer); 54 return true; 55 } 56 57 LockDiscardableMemoryStatus DiscardableMemory::Lock() { 58 DCHECK(!is_locked_); 59 60 int state = VM_PURGABLE_NONVOLATILE; 61 kern_return_t ret = vm_purgable_control( 62 mach_task_self(), 63 reinterpret_cast<vm_address_t>(memory_), 64 VM_PURGABLE_SET_STATE, 65 &state); 66 67 if (ret != KERN_SUCCESS) 68 return DISCARDABLE_MEMORY_FAILED; 69 70 is_locked_ = true; 71 return state & VM_PURGABLE_EMPTY ? DISCARDABLE_MEMORY_PURGED 72 : DISCARDABLE_MEMORY_SUCCESS; 73 } 74 75 void DiscardableMemory::Unlock() { 76 DCHECK(is_locked_); 77 78 int state = VM_PURGABLE_VOLATILE | VM_VOLATILE_GROUP_DEFAULT; 79 kern_return_t ret = vm_purgable_control( 80 mach_task_self(), 81 reinterpret_cast<vm_address_t>(memory_), 82 VM_PURGABLE_SET_STATE, 83 &state); 84 85 if (ret != KERN_SUCCESS) 86 DLOG(ERROR) << "Failed to unlock memory."; 87 88 is_locked_ = false; 89 } 90 91 // static 92 bool DiscardableMemory::PurgeForTestingSupported() { 93 return true; 94 } 95 96 // static 97 void DiscardableMemory::PurgeForTesting() { 98 int state = 0; 99 vm_purgable_control(mach_task_self(), 0, VM_PURGABLE_PURGE_ALL, &state); 100 } 101 102 } // namespace base 103