1/* 2 * Copyright (C) 2010 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "SharedMemory.h" 28 29#include "ArgumentDecoder.h" 30#include "ArgumentEncoder.h" 31#include "Arguments.h" 32#include "MachPort.h" 33#include <mach/mach_port.h> 34#include <mach/mach_vm.h> 35#include <mach/vm_map.h> 36#include <wtf/RefPtr.h> 37 38namespace WebKit { 39 40SharedMemory::Handle::Handle() 41 : m_port(MACH_PORT_NULL) 42 , m_size(0) 43{ 44} 45 46SharedMemory::Handle::~Handle() 47{ 48 if (m_port) 49 mach_port_deallocate(mach_task_self(), m_port); 50} 51 52bool SharedMemory::Handle::isNull() const 53{ 54 return !m_port; 55} 56 57void SharedMemory::Handle::encode(CoreIPC::ArgumentEncoder* encoder) const 58{ 59 encoder->encodeUInt64(m_size); 60 encoder->encode(CoreIPC::MachPort(m_port, MACH_MSG_TYPE_MOVE_SEND)); 61 m_port = MACH_PORT_NULL; 62} 63 64bool SharedMemory::Handle::decode(CoreIPC::ArgumentDecoder* decoder, Handle& handle) 65{ 66 ASSERT(!handle.m_port); 67 ASSERT(!handle.m_size); 68 69 uint64_t size; 70 if (!decoder->decodeUInt64(size)) 71 return false; 72 73 CoreIPC::MachPort machPort; 74 if (!decoder->decode(CoreIPC::Out(machPort))) 75 return false; 76 77 handle.m_size = size; 78 handle.m_port = machPort.port(); 79 return true; 80} 81 82static inline void* toPointer(mach_vm_address_t address) 83{ 84 return reinterpret_cast<void*>(static_cast<uintptr_t>(address)); 85} 86 87static inline mach_vm_address_t toVMAddress(void* pointer) 88{ 89 return static_cast<mach_vm_address_t>(reinterpret_cast<uintptr_t>(pointer)); 90} 91 92PassRefPtr<SharedMemory> SharedMemory::create(size_t size) 93{ 94 ASSERT(size); 95 96 mach_vm_address_t address; 97 kern_return_t kr = mach_vm_allocate(mach_task_self(), &address, round_page(size), VM_FLAGS_ANYWHERE); 98 if (kr != KERN_SUCCESS) 99 return 0; 100 101 // Create a Mach port that represents the shared memory. 102 mach_port_t port; 103 memory_object_size_t memoryObjectSize = round_page(size); 104 kr = mach_make_memory_entry_64(mach_task_self(), &memoryObjectSize, address, VM_PROT_DEFAULT, &port, MACH_PORT_NULL); 105 106 if (kr != KERN_SUCCESS) { 107 mach_vm_deallocate(mach_task_self(), address, round_page(size)); 108 return 0; 109 } 110 111 ASSERT(memoryObjectSize >= round_page(size)); 112 113 RefPtr<SharedMemory> sharedMemory(adoptRef(new SharedMemory)); 114 sharedMemory->m_size = size; 115 sharedMemory->m_data = toPointer(address); 116 sharedMemory->m_port = port; 117 118 return sharedMemory.release(); 119} 120 121static inline vm_prot_t machProtection(SharedMemory::Protection protection) 122{ 123 switch (protection) { 124 case SharedMemory::ReadOnly: 125 return VM_PROT_READ; 126 case SharedMemory::ReadWrite: 127 return VM_PROT_READ | VM_PROT_WRITE; 128 } 129 130 ASSERT_NOT_REACHED(); 131 return VM_PROT_NONE; 132} 133 134PassRefPtr<SharedMemory> SharedMemory::create(const Handle& handle, Protection protection) 135{ 136 if (handle.isNull()) 137 return 0; 138 139 // Map the memory. 140 vm_prot_t vmProtection = machProtection(protection); 141 mach_vm_address_t mappedAddress = 0; 142 kern_return_t kr = mach_vm_map(mach_task_self(), &mappedAddress, handle.m_size, 0, VM_FLAGS_ANYWHERE, handle.m_port, 0, false, vmProtection, vmProtection, VM_INHERIT_NONE); 143 if (kr != KERN_SUCCESS) 144 return 0; 145 146 RefPtr<SharedMemory> sharedMemory(adoptRef(new SharedMemory)); 147 sharedMemory->m_size = handle.m_size; 148 sharedMemory->m_data = toPointer(mappedAddress); 149 sharedMemory->m_port = MACH_PORT_NULL; 150 151 return sharedMemory.release(); 152} 153 154SharedMemory::~SharedMemory() 155{ 156 if (m_data) { 157 kern_return_t kr = mach_vm_deallocate(mach_task_self(), toVMAddress(m_data), round_page(m_size)); 158 ASSERT_UNUSED(kr, kr == KERN_SUCCESS); 159 } 160 161 if (m_port) { 162 kern_return_t kr = mach_port_deallocate(mach_task_self(), m_port); 163 ASSERT_UNUSED(kr, kr == KERN_SUCCESS); 164 } 165} 166 167bool SharedMemory::createHandle(Handle& handle, Protection protection) 168{ 169 ASSERT(!handle.m_port); 170 ASSERT(!handle.m_size); 171 172 mach_vm_address_t address = toVMAddress(m_data); 173 memory_object_size_t size = round_page(m_size); 174 175 mach_port_t port; 176 177 if (protection == ReadWrite && m_port) { 178 // Just re-use the port we have. 179 port = m_port; 180 if (mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, 1) != KERN_SUCCESS) 181 return false; 182 } else { 183 // Create a mach port that represents the shared memory. 184 kern_return_t kr = mach_make_memory_entry_64(mach_task_self(), &size, address, machProtection(protection), &port, MACH_PORT_NULL); 185 if (kr != KERN_SUCCESS) 186 return false; 187 188 ASSERT(size >= round_page(m_size)); 189 } 190 191 handle.m_port = port; 192 handle.m_size = size; 193 194 return true; 195} 196 197unsigned SharedMemory::systemPageSize() 198{ 199 return vm_page_size; 200} 201 202} // namespace WebKit 203