/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "mem_map_arena_pool.h"

#include <sys/mman.h>

#include <algorithm>
#include <cstddef>
#include <iomanip>
#include <numeric>

#include <android-base/logging.h>

#include "base/arena_allocator-inl.h"
#include "base/mem_map.h"
#include "base/systrace.h"
#include "runtime_globals.h"

namespace art HIDDEN {

class MemMapArena final : public Arena {
 public:
  MemMapArena(size_t size, bool low_4gb, const char* name);
  virtual ~MemMapArena();
  void Release() override;

 private:
  static MemMap Allocate(size_t size, bool low_4gb, const char* name);

  MemMap map_;
};

MemMapArena::MemMapArena(size_t size, bool low_4gb, const char* name)
    : map_(Allocate(size, low_4gb, name)) {
  memory_ = map_.Begin();
  static_assert(ArenaAllocator::kArenaAlignment <= kMinPageSize,
                "Arena should not need stronger alignment than kMinPageSize.");
  DCHECK_ALIGNED(memory_, ArenaAllocator::kArenaAlignment);
  size_ = map_.Size();
}

MemMap MemMapArena::Allocate(size_t size, bool low_4gb, const char* name) {
  // Round up to a full page as that's the smallest unit of allocation for mmap()
  // and we want to be able to use all memory that we actually allocate.
  size = RoundUp(size, gPageSize);
  std::string error_msg;
  // TODO(b/278665389): remove this retry logic if the root cause is found.
  constexpr int MAX_RETRY_CNT = 3;
  int retry_cnt = 0;
  while (true) {
    MemMap map = MemMap::MapAnonymous(name, size, PROT_READ | PROT_WRITE, low_4gb, &error_msg);
    if (map.IsValid()) {
      if (retry_cnt > 0) {
        LOG(WARNING) << "Succeed with retry(cnt=" << retry_cnt << ")";
      }
      return map;
    } else {
      if (retry_cnt == MAX_RETRY_CNT) {
        CHECK(map.IsValid()) << error_msg << "(retried " << retry_cnt << " times)";
      }
    }
    retry_cnt++;
    LOG(ERROR) << error_msg << " but retry(cnt=" << retry_cnt << ")";
  }
}

MemMapArena::~MemMapArena() {
  // Destroys MemMap via std::unique_ptr<>.
}

void MemMapArena::Release() {
  if (bytes_allocated_ > 0) {
    map_.MadviseDontNeedAndZero();
    bytes_allocated_ = 0;
  }
}

MemMapArenaPool::MemMapArenaPool(bool low_4gb, const char* name)
    : low_4gb_(low_4gb),
      name_(name),
      free_arenas_(nullptr) {
  MemMap::Init();
}

MemMapArenaPool::~MemMapArenaPool() {
  ReclaimMemory();
}

void MemMapArenaPool::ReclaimMemory() {
  while (free_arenas_ != nullptr) {
    Arena* arena = free_arenas_;
    free_arenas_ = free_arenas_->next_;
    delete arena;
  }
}

void MemMapArenaPool::LockReclaimMemory() {
  std::lock_guard<std::mutex> lock(lock_);
  ReclaimMemory();
}

Arena* MemMapArenaPool::AllocArena(size_t size) {
  Arena* ret = nullptr;
  {
    std::lock_guard<std::mutex> lock(lock_);
    if (free_arenas_ != nullptr && LIKELY(free_arenas_->Size() >= size)) {
      ret = free_arenas_;
      free_arenas_ = free_arenas_->next_;
    }
  }
  if (ret == nullptr) {
    ret = new MemMapArena(size, low_4gb_, name_);
  }
  ret->Reset();
  return ret;
}

void MemMapArenaPool::TrimMaps() {
  ScopedTrace trace(__PRETTY_FUNCTION__);
  std::lock_guard<std::mutex> lock(lock_);
  for (Arena* arena = free_arenas_; arena != nullptr; arena = arena->next_) {
    arena->Release();
  }
}

size_t MemMapArenaPool::GetBytesAllocated() const {
  size_t total = 0;
  std::lock_guard<std::mutex> lock(lock_);
  for (Arena* arena = free_arenas_; arena != nullptr; arena = arena->next_) {
    total += arena->GetBytesAllocated();
  }
  return total;
}

void MemMapArenaPool::FreeArenaChain(Arena* first) {
  if (kRunningOnMemoryTool) {
    for (Arena* arena = first; arena != nullptr; arena = arena->next_) {
      MEMORY_TOOL_MAKE_UNDEFINED(arena->memory_, arena->bytes_allocated_);
    }
  }

  if (arena_allocator::kArenaAllocatorPreciseTracking) {
    // Do not reuse arenas when tracking.
    while (first != nullptr) {
      Arena* next = first->next_;
      delete first;
      first = next;
    }
    return;
  }

  if (first != nullptr) {
    Arena* last = first;
    while (last->next_ != nullptr) {
      last = last->next_;
    }
    std::lock_guard<std::mutex> lock(lock_);
    last->next_ = free_arenas_;
    free_arenas_ = first;
  }
}

}  // namespace art
