chromium/chromeos/ash/components/memory/userspace_swap/region.cc

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos/ash/components/memory/userspace_swap/region.h"

#include <sys/uio.h>

#include <cstdint>
#include <ostream>
#include <string_view>
#include <vector>

#include "base/containers/span.h"

namespace ash {
namespace memory {
namespace userspace_swap {

// AsIovec will return the iovec representation of this Region.
struct iovec COMPONENT_EXPORT(USERSPACE_SWAP) Region::AsIovec() const {
  return {.iov_base = reinterpret_cast<void*>(address), .iov_len = length};
}

std::string_view COMPONENT_EXPORT(
    USERSPACE_SWAP) Region::AsStringPiece() const {
  return std::string_view(reinterpret_cast<char*>(address), length);
}

RegionOverlap COMPONENT_EXPORT(USERSPACE_SWAP) Region::CalculateRegionOverlap(
    const Region& range) const {
  RegionOverlap overlap;

  // We have four possible situations here related to how a region actually fits
  // within a range, as only a portion of a region we manage may have been
  // removed or unmapped. When situations such as 2, 3, and 4 happen we need to
  // deal with them and we will do that by restoring the remaining portion of
  // the region.
  //
  //          [ region_start           region_end ]
  //   1.     [ range_start             range_end ]
  //   2.     [range_start   range_end]
  //   3.                 [range_start   range_end]
  //   4.           [range_start   range_end]
  //
  //   Given these scenarios RemainingRegions will populate |before|
  //   and |after| if there are portions which were unaffected by an
  //   operation. This allows the Removed/Unmapped callbacks to determine how to
  //   restore any memory that was not removed or unmapped.
  uintptr_t region_start = address;
  uintptr_t region_end = address + length;
  uintptr_t range_start = range.address;
  uintptr_t range_end = range.address + range.length;

  CHECK_LE(range_start, range_end);
  CHECK_LE(region_start, region_end);

  if (range_end < region_start || range_start > region_end) {
    return overlap;  // There is no overlap
  }

  // Since we only care about the pieces that related to this region we will
  // clamp range_start and range_end.
  range_start = std::max(range_start, region_start);
  range_end = std::min(range_end, region_end);

  if (range_start > region_start) {
    overlap.before = Region(region_start, range_start - region_start);
  }

  overlap.intersection = Region(range_start, range_end - range_start);

  if (range_end < region_end) {
    overlap.after = Region(range_end, region_end - range_end);
  }

  return overlap;
}

// Easily print a region to a stream, useful for debugging.
std::ostream& COMPONENT_EXPORT(USERSPACE_SWAP) operator<<(
    std::ostream& os,
    const Region& region) {
  os << "[" << reinterpret_cast<void*>(region.address) << "-"
     << reinterpret_cast<void*>(region.address + region.length) << "]";
  return os;
}

RegionOverlap::RegionOverlap() = default;
RegionOverlap::~RegionOverlap() = default;
RegionOverlap::RegionOverlap(const RegionOverlap&) = default;

}  // namespace userspace_swap
}  // namespace memory
}  // namespace ash