Bug 1858509 add thread-safety annotations around MediaSourceDemuxer::mMonitor r=alwu
[gecko.git] / ipc / glue / SharedMemoryBasic_mach.mm
blobd9992792e9bba333a1f17a3bbbe54480403b98ee
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: sw=2 ts=8 et :
3  */
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/. */
8 #include <map>
10 #include <mach/vm_map.h>
11 #include <mach/mach_port.h>
12 #if defined(XP_IOS)
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
19 #else
20 #  include <mach/mach_vm.h>
21 #endif
22 #include <pthread.h>
23 #include <unistd.h>
24 #include "SharedMemoryBasic.h"
26 #include "mozilla/IntegerPrintfMacros.h"
27 #include "mozilla/Printf.h"
28 #include "mozilla/StaticMutex.h"
30 #ifdef DEBUG
31 #  define LOG_ERROR(str, args...)                                  \
32     PR_BEGIN_MACRO                                                 \
33     mozilla::SmprintfPointer msg = mozilla::Smprintf(str, ##args); \
34     NS_WARNING(msg.get());                                         \
35     PR_END_MACRO
36 #else
37 #  define LOG_ERROR(str, args...) \
38     do { /* nothing */            \
39     } while (0)
40 #endif
42 namespace mozilla {
43 namespace ipc {
45 SharedMemoryBasic::SharedMemoryBasic()
46     : mPort(MACH_PORT_NULL), mMemory(nullptr), mOpenRights(RightsReadWrite) {}
48 SharedMemoryBasic::~SharedMemoryBasic() {
49   Unmap();
50   CloseHandle();
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;
58   return true;
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 =
75       mach_make_memory_entry_64(mach_task_self(), &memoryObjectSize, 0,
76                                 MAP_MEM_NAMED_CREATE | VM_PROT_DEFAULT,
77                                 getter_Transfers(mPort), MACH_PORT_NULL);
78   if (kr != KERN_SUCCESS || memoryObjectSize < round_page(size)) {
79     LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n", size,
80               mach_error_string(kr), kr);
81     CloseHandle();
82     return false;
83   }
85   Created(size);
86   return true;
89 bool SharedMemoryBasic::Map(size_t size, void* fixed_address) {
90   MOZ_ASSERT(mMemory == nullptr);
92   if (MACH_PORT_NULL == mPort) {
93     return false;
94   }
96   kern_return_t kr;
97   mach_vm_address_t address = toVMAddress(fixed_address);
99   vm_prot_t vmProtection = VM_PROT_READ;
100   if (mOpenRights == RightsReadWrite) {
101     vmProtection |= VM_PROT_WRITE;
102   }
104   kr = mach_vm_map(mach_task_self(), &address, round_page(size), 0,
105                    fixed_address ? VM_FLAGS_FIXED : VM_FLAGS_ANYWHERE,
106                    mPort.get(), 0, false, vmProtection, vmProtection,
107                    VM_INHERIT_NONE);
108   if (kr != KERN_SUCCESS) {
109     if (!fixed_address) {
110       LOG_ERROR(
111           "Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n",
112           size, mach_task_self(), mach_port_t(mPort.get()),
113           mach_error_string(kr), kr);
114     }
115     return false;
116   }
118   if (fixed_address && fixed_address != toPointer(address)) {
119     kr = vm_deallocate(mach_task_self(), address, size);
120     if (kr != KERN_SUCCESS) {
121       LOG_ERROR("Failed to unmap shared memory at unsuitable address "
122                 "(%zu bytes) from %x, port %x. %s (%x)\n",
123                 size, mach_task_self(), mach_port_t(mPort.get()),
124                 mach_error_string(kr), kr);
125     }
126     return false;
127   }
129   mMemory = toPointer(address);
130   Mapped(size);
131   return true;
134 void* SharedMemoryBasic::FindFreeAddressSpace(size_t size) {
135   mach_vm_address_t address = 0;
136   size = round_page(size);
137   if (mach_vm_map(mach_task_self(), &address, size, 0, VM_FLAGS_ANYWHERE,
138                   MEMORY_OBJECT_NULL, 0, false, VM_PROT_NONE, VM_PROT_NONE,
139                   VM_INHERIT_NONE) != KERN_SUCCESS ||
140       vm_deallocate(mach_task_self(), address, size) != KERN_SUCCESS) {
141     return nullptr;
142   }
143   return toPointer(address);
146 auto SharedMemoryBasic::CloneHandle() -> Handle {
147   return mozilla::RetainMachSendRight(mPort.get());
150 auto SharedMemoryBasic::TakeHandle() -> Handle {
151   mOpenRights = RightsReadWrite;
152   return std::move(mPort);
155 void SharedMemoryBasic::Unmap() {
156   if (!mMemory) {
157     return;
158   }
159   vm_address_t address = toVMAddress(mMemory);
160   kern_return_t kr =
161       vm_deallocate(mach_task_self(), address, round_page(mMappedSize));
162   if (kr != KERN_SUCCESS) {
163     LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n",
164               mach_error_string(kr), kr);
165     return;
166   }
167   mMemory = nullptr;
170 bool SharedMemoryBasic::IsHandleValid(const Handle& aHandle) const {
171   return aHandle != nullptr;
174 }  // namespace ipc
175 }  // namespace mozilla