|  | // Copyright 2015 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/memory/shared_memory_handle.h" | 
|  |  | 
|  | #include <mach/mach_vm.h> | 
|  | #include <stddef.h> | 
|  | #include <sys/mman.h> | 
|  | #include <unistd.h> | 
|  |  | 
|  | #include "base/mac/mac_util.h" | 
|  | #include "base/mac/mach_logging.h" | 
|  | #include "base/posix/eintr_wrapper.h" | 
|  | #include "base/unguessable_token.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | SharedMemoryHandle::SharedMemoryHandle() {} | 
|  |  | 
|  | SharedMemoryHandle::SharedMemoryHandle( | 
|  | const base::FileDescriptor& file_descriptor, | 
|  | size_t size, | 
|  | const base::UnguessableToken& guid) | 
|  | : type_(POSIX), | 
|  | file_descriptor_(file_descriptor), | 
|  | guid_(guid), | 
|  | size_(size) {} | 
|  |  | 
|  | SharedMemoryHandle::SharedMemoryHandle(mach_vm_size_t size, | 
|  | const base::UnguessableToken& guid) { | 
|  | type_ = MACH; | 
|  | mach_port_t named_right; | 
|  | kern_return_t kr = mach_make_memory_entry_64( | 
|  | mach_task_self(), | 
|  | &size, | 
|  | 0,  // Address. | 
|  | MAP_MEM_NAMED_CREATE | VM_PROT_READ | VM_PROT_WRITE, | 
|  | &named_right, | 
|  | MACH_PORT_NULL);  // Parent handle. | 
|  | if (kr != KERN_SUCCESS) { | 
|  | memory_object_ = MACH_PORT_NULL; | 
|  | return; | 
|  | } | 
|  |  | 
|  | memory_object_ = named_right; | 
|  | size_ = size; | 
|  | ownership_passes_to_ipc_ = false; | 
|  | guid_ = guid; | 
|  | } | 
|  |  | 
|  | SharedMemoryHandle::SharedMemoryHandle(mach_port_t memory_object, | 
|  | mach_vm_size_t size, | 
|  | const base::UnguessableToken& guid) | 
|  | : type_(MACH), | 
|  | memory_object_(memory_object), | 
|  | ownership_passes_to_ipc_(false), | 
|  | guid_(guid), | 
|  | size_(size) {} | 
|  |  | 
|  | SharedMemoryHandle SharedMemoryHandle::Duplicate() const { | 
|  | switch (type_) { | 
|  | case POSIX: { | 
|  | if (!IsValid()) | 
|  | return SharedMemoryHandle(); | 
|  | int duped_fd = HANDLE_EINTR(dup(file_descriptor_.fd)); | 
|  | if (duped_fd < 0) | 
|  | return SharedMemoryHandle(); | 
|  | return SharedMemoryHandle(FileDescriptor(duped_fd, true), size_, guid_); | 
|  | } | 
|  | case MACH: { | 
|  | if (!IsValid()) | 
|  | return SharedMemoryHandle(); | 
|  |  | 
|  | // Increment the ref count. | 
|  | kern_return_t kr = mach_port_mod_refs(mach_task_self(), memory_object_, | 
|  | MACH_PORT_RIGHT_SEND, 1); | 
|  | DCHECK_EQ(kr, KERN_SUCCESS); | 
|  | SharedMemoryHandle handle(*this); | 
|  | handle.SetOwnershipPassesToIPC(true); | 
|  | return handle; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | bool SharedMemoryHandle::IsValid() const { | 
|  | switch (type_) { | 
|  | case POSIX: | 
|  | return file_descriptor_.fd >= 0; | 
|  | case MACH: | 
|  | return memory_object_ != MACH_PORT_NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | mach_port_t SharedMemoryHandle::GetMemoryObject() const { | 
|  | DCHECK_EQ(type_, MACH); | 
|  | return memory_object_; | 
|  | } | 
|  |  | 
|  | bool SharedMemoryHandle::MapAt(off_t offset, | 
|  | size_t bytes, | 
|  | void** memory, | 
|  | bool read_only) { | 
|  | DCHECK(IsValid()); | 
|  | switch (type_) { | 
|  | case SharedMemoryHandle::POSIX: | 
|  | *memory = mmap(nullptr, bytes, PROT_READ | (read_only ? 0 : PROT_WRITE), | 
|  | MAP_SHARED, file_descriptor_.fd, offset); | 
|  | return *memory != MAP_FAILED; | 
|  | case SharedMemoryHandle::MACH: | 
|  | kern_return_t kr = mach_vm_map( | 
|  | mach_task_self(), | 
|  | reinterpret_cast<mach_vm_address_t*>(memory),    // Output parameter | 
|  | bytes, | 
|  | 0,                                               // Alignment mask | 
|  | VM_FLAGS_ANYWHERE, | 
|  | memory_object_, | 
|  | offset, | 
|  | FALSE,                                           // Copy | 
|  | VM_PROT_READ | (read_only ? 0 : VM_PROT_WRITE),  // Current protection | 
|  | VM_PROT_WRITE | VM_PROT_READ | VM_PROT_IS_MASK,  // Maximum protection | 
|  | VM_INHERIT_NONE); | 
|  | return kr == KERN_SUCCESS; | 
|  | } | 
|  | } | 
|  |  | 
|  | void SharedMemoryHandle::Close() const { | 
|  | if (!IsValid()) | 
|  | return; | 
|  |  | 
|  | switch (type_) { | 
|  | case POSIX: | 
|  | if (IGNORE_EINTR(close(file_descriptor_.fd)) < 0) | 
|  | DPLOG(ERROR) << "Error closing fd"; | 
|  | break; | 
|  | case MACH: | 
|  | kern_return_t kr = mach_port_deallocate(mach_task_self(), memory_object_); | 
|  | if (kr != KERN_SUCCESS) | 
|  | MACH_DLOG(ERROR, kr) << "Error deallocating mach port"; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | void SharedMemoryHandle::SetOwnershipPassesToIPC(bool ownership_passes) { | 
|  | DCHECK_EQ(type_, MACH); | 
|  | ownership_passes_to_ipc_ = ownership_passes; | 
|  | } | 
|  |  | 
|  | bool SharedMemoryHandle::OwnershipPassesToIPC() const { | 
|  | DCHECK_EQ(type_, MACH); | 
|  | return ownership_passes_to_ipc_; | 
|  | } | 
|  |  | 
|  | }  // namespace base |