1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
10 #include <mach/vm_map.h>
11 #include <mach/mach_port.h>
13 # include <mach/vm_map.h>
14 # define mach_vm_address_t vm_address_t
15 # define mach_vm_map vm_map
16 # define mach_vm_read vm_read
17 # define mach_vm_region_recurse vm_region_recurse_64
18 # define mach_vm_size_t vm_size_t
20 # include <mach/mach_vm.h>
24 #include "SharedMemoryBasic.h"
26 #include "mozilla/IntegerPrintfMacros.h"
27 #include "mozilla/Printf.h"
28 #include "mozilla/StaticMutex.h"
31 # define LOG_ERROR(str, args...) \
33 mozilla::SmprintfPointer msg = mozilla::Smprintf(str, ##args); \
34 NS_WARNING(msg.get()); \
37 # define LOG_ERROR(str, args...) \
45 SharedMemoryBasic::SharedMemoryBasic()
46 : mPort(MACH_PORT_NULL), mMemory(nullptr), mOpenRights(RightsReadWrite) {}
48 SharedMemoryBasic::~SharedMemoryBasic() {
53 bool SharedMemoryBasic::SetHandle(Handle aHandle, OpenRights aRights) {
54 MOZ_ASSERT(mPort == MACH_PORT_NULL, "already initialized");
56 mPort = std::move(aHandle);
57 mOpenRights = aRights;
61 static inline void* toPointer(mach_vm_address_t address) {
62 return reinterpret_cast<void*>(static_cast<uintptr_t>(address));
65 static inline mach_vm_address_t toVMAddress(void* pointer) {
66 return static_cast<mach_vm_address_t>(reinterpret_cast<uintptr_t>(pointer));
69 bool SharedMemoryBasic::Create(size_t size) {
70 MOZ_ASSERT(mPort == MACH_PORT_NULL, "already initialized");
72 memory_object_size_t memoryObjectSize = round_page(size);
74 kern_return_t kr = mach_make_memory_entry_64(mach_task_self(), &memoryObjectSize, 0,
75 MAP_MEM_NAMED_CREATE | VM_PROT_DEFAULT,
76 getter_Transfers(mPort), MACH_PORT_NULL);
77 if (kr != KERN_SUCCESS || memoryObjectSize < round_page(size)) {
78 LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n", size, mach_error_string(kr),
88 bool SharedMemoryBasic::Map(size_t size, void* fixed_address) {
89 MOZ_ASSERT(mMemory == nullptr);
91 if (MACH_PORT_NULL == mPort) {
96 mach_vm_address_t address = toVMAddress(fixed_address);
98 vm_prot_t vmProtection = VM_PROT_READ;
99 if (mOpenRights == RightsReadWrite) {
100 vmProtection |= VM_PROT_WRITE;
103 kr = mach_vm_map(mach_task_self(), &address, round_page(size), 0,
104 fixed_address ? VM_FLAGS_FIXED : VM_FLAGS_ANYWHERE, mPort.get(), 0, false,
105 vmProtection, vmProtection, VM_INHERIT_NONE);
106 if (kr != KERN_SUCCESS) {
107 if (!fixed_address) {
108 LOG_ERROR("Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n", size,
109 mach_task_self(), mach_port_t(mPort.get()), mach_error_string(kr), kr);
114 if (fixed_address && fixed_address != toPointer(address)) {
115 kr = vm_deallocate(mach_task_self(), address, size);
116 if (kr != KERN_SUCCESS) {
117 LOG_ERROR("Failed to unmap shared memory at unsuitable address "
118 "(%zu bytes) from %x, port %x. %s (%x)\n",
119 size, mach_task_self(), mach_port_t(mPort.get()), mach_error_string(kr), kr);
124 mMemory = toPointer(address);
129 void* SharedMemoryBasic::FindFreeAddressSpace(size_t size) {
130 mach_vm_address_t address = 0;
131 size = round_page(size);
132 if (mach_vm_map(mach_task_self(), &address, size, 0, VM_FLAGS_ANYWHERE, MEMORY_OBJECT_NULL, 0,
133 false, VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_NONE) != KERN_SUCCESS ||
134 vm_deallocate(mach_task_self(), address, size) != KERN_SUCCESS) {
137 return toPointer(address);
140 auto SharedMemoryBasic::CloneHandle() -> Handle {
141 return mozilla::RetainMachSendRight(mPort.get());
144 void SharedMemoryBasic::Unmap() {
148 vm_address_t address = toVMAddress(mMemory);
149 kern_return_t kr = vm_deallocate(mach_task_self(), address, round_page(mMappedSize));
150 if (kr != KERN_SUCCESS) {
151 LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n", mach_error_string(kr), kr);
157 void SharedMemoryBasic::CloseHandle() {
160 mOpenRights = RightsReadWrite;
164 bool SharedMemoryBasic::IsHandleValid(const Handle& aHandle) const { return aHandle != nullptr; }
167 } // namespace mozilla