Backed out 2 changesets (bug 1943998) for causing wd failures @ phases.py CLOSED...
[gecko.git] / ipc / glue / SharedMemoryPlatform_mach.cpp
blobab95054e332e0bfb3f0b77b3abbfd0646ca91de8
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "SharedMemoryPlatform.h"
9 #include <utility>
11 #include <mach/vm_map.h>
12 #include <mach/mach_port.h>
13 #if defined(XP_IOS)
14 # include <mach/vm_map.h>
15 # define mach_vm_address_t vm_address_t
16 # define mach_vm_map vm_map
17 # define mach_vm_read vm_read
18 # define mach_vm_region_recurse vm_region_recurse_64
19 # define mach_vm_size_t vm_size_t
20 #else
21 # include <mach/mach_vm.h>
22 #endif
23 #include <pthread.h>
24 #include <sys/mman.h> // mprotect
25 #include <unistd.h>
27 #if defined(XP_MACOSX) && defined(__x86_64__)
28 # include "prenv.h"
29 #endif
31 #include "mozilla/IntegerPrintfMacros.h"
32 #include "mozilla/Printf.h"
34 #ifdef DEBUG
35 # define LOG_ERROR(str, args...) \
36 PR_BEGIN_MACRO \
37 mozilla::SmprintfPointer msg = mozilla::Smprintf(str, ##args); \
38 NS_WARNING(msg.get()); \
39 PR_END_MACRO
40 #else
41 # define LOG_ERROR(str, args...) \
42 do { /* nothing */ \
43 } while (0)
44 #endif
46 namespace mozilla::ipc::shared_memory {
48 static inline void* toPointer(mach_vm_address_t aAddress) {
49 return reinterpret_cast<void*>(static_cast<uintptr_t>(aAddress));
52 static inline mach_vm_address_t toVMAddress(void* aPointer) {
53 return static_cast<mach_vm_address_t>(reinterpret_cast<uintptr_t>(aPointer));
56 static Maybe<PlatformHandle> CreateImpl(size_t aSize, bool aFreezable) {
57 memory_object_size_t memoryObjectSize = round_page(aSize);
58 PlatformHandle handle;
60 kern_return_t kr =
61 mach_make_memory_entry_64(mach_task_self(), &memoryObjectSize, 0,
62 MAP_MEM_NAMED_CREATE | VM_PROT_DEFAULT,
63 getter_Transfers(handle), MACH_PORT_NULL);
64 if (kr != KERN_SUCCESS || memoryObjectSize < round_page(aSize)) {
65 LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n", aSize,
66 mach_error_string(kr), kr);
67 return Nothing();
69 return Some(std::move(handle));
72 bool Platform::Create(Handle& aHandle, size_t aSize) {
73 if (auto ph = CreateImpl(aSize, false)) {
74 aHandle.mHandle = std::move(*ph);
75 aHandle.mSize = aSize;
76 return true;
78 return false;
81 bool Platform::CreateFreezable(FreezableHandle& aHandle, size_t aSize) {
82 if (auto ph = CreateImpl(aSize, true)) {
83 aHandle.mHandle = std::move(*ph);
84 aHandle.mSize = aSize;
85 return true;
87 return false;
90 PlatformHandle Platform::CloneHandle(const PlatformHandle& aHandle) {
91 return mozilla::RetainMachSendRight(aHandle.get());
94 static Maybe<void*> MapMemory(size_t aSize, void* aFixedAddress,
95 const mozilla::UniqueMachSendRight& aPort,
96 bool aReadOnly) {
97 kern_return_t kr;
98 mach_vm_address_t address = toVMAddress(aFixedAddress);
100 vm_prot_t vmProtection = VM_PROT_READ;
101 if (!aReadOnly) {
102 vmProtection |= VM_PROT_WRITE;
105 kr = mach_vm_map(mach_task_self(), &address, round_page(aSize), 0,
106 aFixedAddress ? VM_FLAGS_FIXED : VM_FLAGS_ANYWHERE,
107 aPort.get(), 0, false, vmProtection, vmProtection,
108 VM_INHERIT_NONE);
109 if (kr != KERN_SUCCESS) {
110 if (!aFixedAddress) {
111 LOG_ERROR(
112 "Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n",
113 aSize, mach_task_self(), mach_port_t(aPort.get()),
114 mach_error_string(kr), kr);
116 return Nothing();
119 if (aFixedAddress && aFixedAddress != toPointer(address)) {
120 kr = vm_deallocate(mach_task_self(), address, aSize);
121 if (kr != KERN_SUCCESS) {
122 LOG_ERROR(
123 "Failed to unmap shared memory at unsuitable address "
124 "(%zu bytes) from %x, port %x. %s (%x)\n",
125 aSize, mach_task_self(), mach_port_t(aPort.get()),
126 mach_error_string(kr), kr);
128 return Nothing();
131 return Some(toPointer(address));
134 bool Platform::Freeze(FreezableHandle& aHandle) {
135 memory_object_size_t memoryObjectSize = round_page(aHandle.Size());
137 mozilla::UniqueMachSendRight port;
139 // Temporarily map memory (as readonly) to get an address.
140 auto memory = MapMemory(memoryObjectSize, nullptr, aHandle.mHandle, true);
141 if (!memory) {
142 return false;
145 kern_return_t kr = mach_make_memory_entry_64(
146 mach_task_self(), &memoryObjectSize,
147 static_cast<memory_object_offset_t>(reinterpret_cast<uintptr_t>(*memory)),
148 VM_PROT_READ, getter_Transfers(port), MACH_PORT_NULL);
150 // Immediately try to deallocate, regardless of success.
152 kern_return_t kr =
153 vm_deallocate(mach_task_self(), toVMAddress(*memory), memoryObjectSize);
154 if (kr != KERN_SUCCESS) {
155 LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n",
156 mach_error_string(kr), kr);
160 if (kr != KERN_SUCCESS || memoryObjectSize < round_page(aHandle.Size())) {
161 LOG_ERROR("Failed to make memory entry (%llu bytes). %s (%x)\n",
162 aHandle.Size(), mach_error_string(kr), kr);
163 return false;
166 aHandle.mHandle = std::move(port);
168 return true;
171 Maybe<void*> Platform::Map(const HandleBase& aHandle, void* aFixedAddress,
172 bool aReadOnly) {
173 return MapMemory(aHandle.Size(), aFixedAddress, aHandle.mHandle, aReadOnly);
176 void Platform::Unmap(void* aMemory, size_t aSize) {
177 vm_address_t vm_address = toVMAddress(aMemory);
178 kern_return_t kr =
179 vm_deallocate(mach_task_self(), vm_address, round_page(aSize));
180 if (kr != KERN_SUCCESS) {
181 LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n",
182 mach_error_string(kr), kr);
186 bool Platform::Protect(char* aAddr, size_t aSize, Access aAccess) {
187 int flags = PROT_NONE;
188 if (aAccess & AccessRead) flags |= PROT_READ;
189 if (aAccess & AccessWrite) flags |= PROT_WRITE;
191 return 0 == mprotect(aAddr, aSize, flags);
194 void* Platform::FindFreeAddressSpace(size_t aSize) {
195 mach_vm_address_t address = 0;
196 aSize = round_page(aSize);
197 if (mach_vm_map(mach_task_self(), &address, aSize, 0, VM_FLAGS_ANYWHERE,
198 MEMORY_OBJECT_NULL, 0, false, VM_PROT_NONE, VM_PROT_NONE,
199 VM_INHERIT_NONE) != KERN_SUCCESS ||
200 vm_deallocate(mach_task_self(), address, aSize) != KERN_SUCCESS) {
201 return nullptr;
203 return toPointer(address);
206 size_t Platform::PageSize() {
207 #if defined(XP_MACOSX) && defined(__x86_64__)
208 static std::atomic<size_t> sPageSizeOverride = 0;
210 if (sPageSizeOverride == 0) {
211 if (PR_GetEnv("MOZ_SHMEM_PAGESIZE_16K")) {
212 sPageSizeOverride = 16 * 1024;
213 } else {
214 sPageSizeOverride = sysconf(_SC_PAGESIZE);
217 return sPageSizeOverride;
218 #else
219 return sysconf(_SC_PAGESIZE);
220 #endif
223 bool Platform::IsSafeToMap(const PlatformHandle&) { return true; }
225 } // namespace mozilla::ipc::shared_memory