1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/memory/discardable_memory_emulated.h"
6
7#include "base/lazy_instance.h"
8#include "base/memory/discardable_memory_manager.h"
9
10namespace base {
11namespace {
12
13// This is admittedly pretty magical.
14const size_t kEmulatedMemoryLimit = 512 * 1024 * 1024;
15const size_t kEmulatedSoftMemoryLimit = 32 * 1024 * 1024;
16const size_t kEmulatedHardMemoryLimitExpirationTimeMs = 1000;
17
18struct SharedState {
19  SharedState()
20      : manager(kEmulatedMemoryLimit,
21                kEmulatedSoftMemoryLimit,
22                TimeDelta::FromMilliseconds(
23                    kEmulatedHardMemoryLimitExpirationTimeMs)) {}
24
25  internal::DiscardableMemoryManager manager;
26};
27LazyInstance<SharedState>::Leaky g_shared_state = LAZY_INSTANCE_INITIALIZER;
28
29}  // namespace
30
31namespace internal {
32
33DiscardableMemoryEmulated::DiscardableMemoryEmulated(size_t bytes)
34    : bytes_(bytes),
35      is_locked_(false) {
36  g_shared_state.Pointer()->manager.Register(this, bytes);
37}
38
39DiscardableMemoryEmulated::~DiscardableMemoryEmulated() {
40  if (is_locked_)
41    Unlock();
42  g_shared_state.Pointer()->manager.Unregister(this);
43}
44
45// static
46bool DiscardableMemoryEmulated::ReduceMemoryUsage() {
47  return g_shared_state.Pointer()->manager.ReduceMemoryUsage();
48}
49
50// static
51void DiscardableMemoryEmulated::ReduceMemoryUsageUntilWithinLimit(
52    size_t bytes) {
53  g_shared_state.Pointer()->manager.ReduceMemoryUsageUntilWithinLimit(bytes);
54}
55
56// static
57void DiscardableMemoryEmulated::PurgeForTesting() {
58  g_shared_state.Pointer()->manager.PurgeAll();
59}
60
61bool DiscardableMemoryEmulated::Initialize() {
62  return Lock() != DISCARDABLE_MEMORY_LOCK_STATUS_FAILED;
63}
64
65DiscardableMemoryLockStatus DiscardableMemoryEmulated::Lock() {
66  DCHECK(!is_locked_);
67
68  bool purged = false;
69  if (!g_shared_state.Pointer()->manager.AcquireLock(this, &purged))
70    return DISCARDABLE_MEMORY_LOCK_STATUS_FAILED;
71
72  is_locked_ = true;
73  return purged ? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED
74                : DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS;
75}
76
77void DiscardableMemoryEmulated::Unlock() {
78  DCHECK(is_locked_);
79  g_shared_state.Pointer()->manager.ReleaseLock(this);
80  is_locked_ = false;
81}
82
83void* DiscardableMemoryEmulated::Memory() const {
84  DCHECK(is_locked_);
85  DCHECK(memory_);
86  return memory_.get();
87}
88
89bool DiscardableMemoryEmulated::AllocateAndAcquireLock() {
90  if (memory_)
91    return true;
92
93  memory_.reset(new uint8[bytes_]);
94  return false;
95}
96
97void DiscardableMemoryEmulated::Purge() {
98  memory_.reset();
99}
100
101}  // namespace internal
102}  // namespace base
103