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 11namespace base { 12 13namespace { 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). 18const int kDiscardableMemoryTag = VM_MAKE_TAG(252); 19 20} // namespace 21 22// static 23bool DiscardableMemory::Supported() { 24 return true; 25} 26 27DiscardableMemory::~DiscardableMemory() { 28 if (memory_) { 29 vm_deallocate(mach_task_self(), 30 reinterpret_cast<vm_address_t>(memory_), 31 size_); 32 } 33} 34 35bool 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 57LockDiscardableMemoryStatus 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 75void 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 92bool DiscardableMemory::PurgeForTestingSupported() { 93 return true; 94} 95 96// static 97void 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