text: // Copyright 2018 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 "mojo/core/platform_shared_memory_mapping.h"
  
  #include <utility>
  
  #include "base/logging.h"
  #include "base/memory/read_only_shared_memory_region.h"
  #include "base/memory/unsafe_shared_memory_region.h"
  #include "base/memory/writable_shared_memory_region.h"
  #include "base/system/sys_info.h"
  #include "build/build_config.h"
  
  #if defined(OS_NACL)
  // For getpagesize() on NaCl.
  #include <unistd.h>
  #endif
  
  namespace mojo {
  namespace core {
  
  namespace {
  
  size_t GetPageSize() {
  #if defined(OS_NACL)
    // base::SysInfo isn't available under NaCl.
    return getpagesize();
  #else
    return base::SysInfo::VMAllocationGranularity();
  #endif
  }
  
  }  // namespace
  
  PlatformSharedMemoryMapping::PlatformSharedMemoryMapping(
      base::subtle::PlatformSharedMemoryRegion* region,
      size_t offset,
      size_t length)
      : type_(region->GetMode() ==
                      base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly
                  ? Type::kReadOnly
                  : Type::kWritable),
        offset_(offset),
        length_(length) {
    // Mojo shared buffers can be mapped at any offset, but //base shared memory
    // regions must be mapped at a page boundary. We calculate the nearest whole
    // page offset and map from there.
    size_t offset_rounding = offset_ % GetPageSize();
    off_t real_offset = static_cast<off_t>(offset_ - offset_rounding);
    size_t real_length = length_ + offset_rounding;
    void* mapped_memory = nullptr;
    if (type_ == Type::kReadOnly) {
      auto read_only_region =
          base::ReadOnlySharedMemoryRegion::Deserialize(std::move(*region));
      auto read_only_mapping = read_only_region.MapAt(real_offset, real_length);
      mapped_memory = const_cast<void*>(read_only_mapping.memory());
      mapping_ = std::make_unique<base::ReadOnlySharedMemoryMapping>(
          std::move(read_only_mapping));
      *region = base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization(
          std::move(read_only_region));
    } else if (region->GetMode() ==
               base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe) {
      auto unsafe_region =
          base::UnsafeSharedMemoryRegion::Deserialize(std::move(*region));
      auto writable_mapping = unsafe_region.MapAt(real_offset, real_length);
      mapped_memory = writable_mapping.memory();
      mapping_ = std::make_unique<base::WritableSharedMemoryMapping>(
          std::move(writable_mapping));
      *region = base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
          std::move(unsafe_region));
    } else {
      DCHECK_EQ(region->GetMode(),
                base::subtle::PlatformSharedMemoryRegion::Mode::kWritable);
      auto writable_region =
          base::WritableSharedMemoryRegion::Deserialize(std::move(*region));
      auto writable_mapping = writable_region.MapAt(real_offset, real_length);
      mapped_memory = writable_mapping.memory();
      mapping_ = std::make_unique<base::WritableSharedMemoryMapping>(
          std::move(writable_mapping));
      *region = base::WritableSharedMemoryRegion::TakeHandleForSerialization(
          std::move(writable_region));
    }
  
    base_ = static_cast<char*>(mapped_memory) + offset_rounding;
  }
  
  PlatformSharedMemoryMapping::~PlatformSharedMemoryMapping() = default;
  
  bool PlatformSharedMemoryMapping::IsValid() const {
    return mapping_ && mapping_->IsValid();
  }
  
  void* PlatformSharedMemoryMapping::GetBase() const {
    return base_;
  }
  
  size_t PlatformSharedMemoryMapping::GetLength() const {
    return length_;
  }
  
  }  // namespace core
  }  // namespace mojo
  