普通文本  |  147行  |  3.99 KB

// 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