|  | // Copyright 2017 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.h" | 
|  |  | 
|  | #include <limits> | 
|  |  | 
|  | #include <lib/zx/vmar.h> | 
|  | #include <lib/zx/vmo.h> | 
|  | #include <zircon/rights.h> | 
|  |  | 
|  | #include "base/bits.h" | 
|  | #include "base/fuchsia/fuchsia_logging.h" | 
|  | #include "base/memory/shared_memory_tracker.h" | 
|  | #include "base/process/process_metrics.h" | 
|  | #include "starboard/types.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | SharedMemory::SharedMemory() {} | 
|  |  | 
|  | SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only) | 
|  | : shm_(handle), read_only_(read_only) {} | 
|  |  | 
|  | SharedMemory::~SharedMemory() { | 
|  | Unmap(); | 
|  | Close(); | 
|  | } | 
|  |  | 
|  | // static | 
|  | bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) { | 
|  | return handle.IsValid(); | 
|  | } | 
|  |  | 
|  | // static | 
|  | void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) { | 
|  | DCHECK(handle.IsValid()); | 
|  | handle.Close(); | 
|  | } | 
|  |  | 
|  | // static | 
|  | size_t SharedMemory::GetHandleLimit() { | 
|  | // Duplicated from the internal Magenta kernel constant kMaxHandleCount | 
|  | // (kernel/lib/zircon/zircon.cpp). | 
|  | return 256 * 1024u; | 
|  | } | 
|  |  | 
|  | bool SharedMemory::CreateAndMapAnonymous(size_t size) { | 
|  | return CreateAnonymous(size) && Map(size); | 
|  | } | 
|  |  | 
|  | bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { | 
|  | requested_size_ = options.size; | 
|  | mapped_size_ = bits::Align(requested_size_, GetPageSize()); | 
|  | zx::vmo vmo; | 
|  | zx_status_t status = zx::vmo::create(mapped_size_, 0, &vmo); | 
|  | if (status != ZX_OK) { | 
|  | ZX_DLOG(ERROR, status) << "zx_vmo_create"; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (!options.executable) { | 
|  | // If options.executable isn't set, drop that permission by replacement. | 
|  | const int kNoExecFlags = ZX_DEFAULT_VMO_RIGHTS & ~ZX_RIGHT_EXECUTE; | 
|  | status = vmo.replace(kNoExecFlags, &vmo); | 
|  | if (status != ZX_OK) { | 
|  | ZX_DLOG(ERROR, status) << "zx_handle_replace"; | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | shm_ = SharedMemoryHandle(vmo.release(), mapped_size_, | 
|  | UnguessableToken::Create()); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool SharedMemory::MapAt(off_t offset, size_t bytes) { | 
|  | if (!shm_.IsValid()) | 
|  | return false; | 
|  |  | 
|  | if (bytes > static_cast<size_t>(std::numeric_limits<int>::max())) | 
|  | return false; | 
|  |  | 
|  | if (memory_) | 
|  | return false; | 
|  |  | 
|  | int flags = ZX_VM_FLAG_PERM_READ; | 
|  | if (!read_only_) | 
|  | flags |= ZX_VM_FLAG_PERM_WRITE; | 
|  | uintptr_t addr; | 
|  | zx_status_t status = zx::vmar::root_self()->map( | 
|  | 0, *zx::unowned_vmo(shm_.GetHandle()), offset, bytes, flags, &addr); | 
|  | if (status != ZX_OK) { | 
|  | ZX_DLOG(ERROR, status) << "zx_vmar_map"; | 
|  | return false; | 
|  | } | 
|  | memory_ = reinterpret_cast<void*>(addr); | 
|  |  | 
|  | mapped_size_ = bytes; | 
|  | mapped_id_ = shm_.GetGUID(); | 
|  | SharedMemoryTracker::GetInstance()->IncrementMemoryUsage(*this); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool SharedMemory::Unmap() { | 
|  | if (!memory_) | 
|  | return false; | 
|  |  | 
|  | SharedMemoryTracker::GetInstance()->DecrementMemoryUsage(*this); | 
|  |  | 
|  | uintptr_t addr = reinterpret_cast<uintptr_t>(memory_); | 
|  | zx_status_t status = zx::vmar::root_self()->unmap(addr, mapped_size_); | 
|  | if (status != ZX_OK) { | 
|  | ZX_DLOG(ERROR, status) << "zx_vmar_unmap"; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | memory_ = nullptr; | 
|  | mapped_id_ = UnguessableToken(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void SharedMemory::Close() { | 
|  | if (shm_.IsValid()) { | 
|  | shm_.Close(); | 
|  | shm_ = SharedMemoryHandle(); | 
|  | } | 
|  | } | 
|  |  | 
|  | SharedMemoryHandle SharedMemory::handle() const { | 
|  | return shm_; | 
|  | } | 
|  |  | 
|  | SharedMemoryHandle SharedMemory::TakeHandle() { | 
|  | SharedMemoryHandle handle(shm_); | 
|  | handle.SetOwnershipPassesToIPC(true); | 
|  | Unmap(); | 
|  | shm_ = SharedMemoryHandle(); | 
|  | return handle; | 
|  | } | 
|  |  | 
|  | SharedMemoryHandle SharedMemory::DuplicateHandle( | 
|  | const SharedMemoryHandle& handle) { | 
|  | return handle.Duplicate(); | 
|  | } | 
|  |  | 
|  | SharedMemoryHandle SharedMemory::GetReadOnlyHandle() const { | 
|  | zx::vmo duped_handle; | 
|  | const int kNoWriteOrExec = | 
|  | ZX_DEFAULT_VMO_RIGHTS & | 
|  | ~(ZX_RIGHT_WRITE | ZX_RIGHT_EXECUTE | ZX_RIGHT_SET_PROPERTY); | 
|  | zx_status_t status = zx::unowned_vmo(shm_.GetHandle()) | 
|  | ->duplicate(kNoWriteOrExec, &duped_handle); | 
|  | if (status != ZX_OK) | 
|  | return SharedMemoryHandle(); | 
|  |  | 
|  | SharedMemoryHandle handle(duped_handle.release(), shm_.GetSize(), | 
|  | shm_.GetGUID()); | 
|  | handle.SetOwnershipPassesToIPC(true); | 
|  | return handle; | 
|  | } | 
|  |  | 
|  | }  // namespace base |