blob: 4db9edbc5b69527cf590d78c343396c760fe061c [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 <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"
#include "starboard/types.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