1// Copyright 2014 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#ifndef BASE_MAC_SCOPED_MACH_VM_H_ 6#define BASE_MAC_SCOPED_MACH_VM_H_ 7 8#include <mach/mach.h> 9 10#include <algorithm> 11 12#include "base/base_export.h" 13#include "base/basictypes.h" 14#include "base/logging.h" 15 16// Use ScopedMachVM to supervise ownership of pages in the current process 17// through the Mach VM subsystem. Pages allocated with vm_allocate can be 18// released when exiting a scope with ScopedMachVM. 19// 20// The Mach VM subsystem operates on a page-by-page basis, and a single VM 21// allocation managed by a ScopedMachVM object may span multiple pages. As far 22// as Mach is concerned, allocated pages may be deallocated individually. This 23// is in contrast to higher-level allocators such as malloc, where the base 24// address of an allocation implies the size of an allocated block. 25// Consequently, it is not sufficient to just pass the base address of an 26// allocation to ScopedMachVM, it also needs to know the size of the 27// allocation. To avoid any confusion, both the base address and size must 28// be page-aligned. 29// 30// When dealing with Mach VM, base addresses will naturally be page-aligned, 31// but user-specified sizes may not be. If there's a concern that a size is 32// not page-aligned, use the mach_vm_round_page macro to correct it. 33// 34// Example: 35// 36// vm_address_t address = 0; 37// vm_size_t size = 12345; // This requested size is not page-aligned. 38// kern_return_t kr = 39// vm_allocate(mach_task_self(), &address, size, VM_FLAGS_ANYWHERE); 40// if (kr != KERN_SUCCESS) { 41// return false; 42// } 43// ScopedMachVM vm_owner(address, mach_vm_round_page(size)); 44 45namespace base { 46namespace mac { 47 48class BASE_EXPORT ScopedMachVM { 49 public: 50 explicit ScopedMachVM(vm_address_t address = 0, vm_size_t size = 0) 51 : address_(address), 52 size_(size) { 53 DCHECK(address % PAGE_SIZE == 0); 54 DCHECK(size % PAGE_SIZE == 0); 55 } 56 57 ~ScopedMachVM() { 58 if (size_) { 59 vm_deallocate(mach_task_self(), address_, size_); 60 } 61 } 62 63 void reset(vm_address_t address = 0, vm_size_t size = 0); 64 65 vm_address_t address() const { 66 return address_; 67 } 68 69 vm_size_t size() const { 70 return size_; 71 } 72 73 void swap(ScopedMachVM& that) { 74 std::swap(address_, that.address_); 75 std::swap(size_, that.size_); 76 } 77 78 void release() { 79 address_ = 0; 80 size_ = 0; 81 } 82 83 private: 84 vm_address_t address_; 85 vm_size_t size_; 86 87 DISALLOW_COPY_AND_ASSIGN(ScopedMachVM); 88}; 89 90} // namespace mac 91} // namespace base 92 93#endif // BASE_MAC_SCOPED_MACH_VM_H_ 94