blob: ad470bea8169b944efbf293a878e6a488cd3cc77 [file] [log] [blame]
// 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/posix/eintr_wrapper.h"
namespace base {
SharedMemoryHandle::SharedMemoryHandle() {}
SharedMemoryHandle::SharedMemoryHandle(mach_vm_size_t size) {
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;
pid_ = GetCurrentProcId();
ownership_passes_to_ipc_ = false;
}
SharedMemoryHandle::SharedMemoryHandle(mach_port_t memory_object,
mach_vm_size_t size,
base::ProcessId pid)
: memory_object_(memory_object),
size_(size),
pid_(pid),
ownership_passes_to_ipc_(false) {}
SharedMemoryHandle::SharedMemoryHandle(const SharedMemoryHandle& handle) {
CopyRelevantData(handle);
}
SharedMemoryHandle& SharedMemoryHandle::operator=(
const SharedMemoryHandle& handle) {
if (this == &handle)
return *this;
CopyRelevantData(handle);
return *this;
}
SharedMemoryHandle SharedMemoryHandle::Duplicate() const {
if (!IsValid())
return SharedMemoryHandle(MACH_PORT_NULL, 0, 0);
// 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::operator==(const SharedMemoryHandle& handle) const {
if (!IsValid() && !handle.IsValid())
return true;
return memory_object_ == handle.memory_object_ && size_ == handle.size_ &&
pid_ == handle.pid_;
}
bool SharedMemoryHandle::operator!=(const SharedMemoryHandle& handle) const {
return !(*this == handle);
}
bool SharedMemoryHandle::IsValid() const {
return memory_object_ != MACH_PORT_NULL;
}
mach_port_t SharedMemoryHandle::GetMemoryObject() const {
return memory_object_;
}
bool SharedMemoryHandle::GetSize(size_t* size) const {
if (!IsValid()) {
*size = 0;
return true;
}
*size = size_;
return true;
}
bool SharedMemoryHandle::MapAt(off_t offset,
size_t bytes,
void** memory,
bool read_only) {
DCHECK(IsValid());
DCHECK_EQ(pid_, GetCurrentProcId());
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;
kern_return_t kr = mach_port_deallocate(mach_task_self(), memory_object_);
if (kr != KERN_SUCCESS)
DPLOG(ERROR) << "Error deallocating mach port: " << kr;
}
void SharedMemoryHandle::SetOwnershipPassesToIPC(bool ownership_passes) {
ownership_passes_to_ipc_ = ownership_passes;
}
bool SharedMemoryHandle::OwnershipPassesToIPC() const {
return ownership_passes_to_ipc_;
}
void SharedMemoryHandle::CopyRelevantData(const SharedMemoryHandle& handle) {
memory_object_ = handle.memory_object_;
size_ = handle.size_;
pid_ = handle.pid_;
ownership_passes_to_ipc_ = handle.ownership_passes_to_ipc_;
}
} // namespace base