OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/memory/discardable_memory_mach.h" | 5 #include "base/memory/discardable_memory_mach.h" |
6 | 6 |
7 #include <mach/mach.h> | 7 #include <mach/mach.h> |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
11 #include "base/lazy_instance.h" | 11 #include "base/lazy_instance.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/mac/mach_logging.h" | 13 #include "base/mac/mach_logging.h" |
14 | 14 |
15 namespace base { | 15 namespace base { |
16 namespace { | 16 namespace { |
17 | 17 |
18 // For Mach, have the DiscardableMemoryManager trigger userspace eviction when | 18 // For Mach, have the DiscardableMemoryManager trigger userspace eviction when |
19 // address space usage gets too high (e.g. 512 MBytes). | 19 // address space usage gets too high (e.g. 512 MBytes). |
20 const size_t kMachMemoryLimit = 512 * 1024 * 1024; | 20 const size_t kMachMemoryLimit = 512 * 1024 * 1024; |
21 | 21 |
22 struct SharedState { | 22 // internal::DiscardableMemoryManager has an explicit constructor that takes |
23 SharedState() | 23 // a number of memory limit parameters. The LeakyLazyInstanceTraits doesn't |
24 : manager(kMachMemoryLimit, kMachMemoryLimit, TimeDelta::Max()) {} | 24 // handle the case. Thus, we need our own class here. |
| 25 struct DiscardableMemoryManagerLazyInstanceTraits { |
| 26 // Leaky as discardable memory clients can use this after the exit handler |
| 27 // has been called. |
| 28 static const bool kRegisterOnExit = false; |
| 29 #ifndef NDEBUG |
| 30 static const bool kAllowedToAccessOnNonjoinableThread = true; |
| 31 #endif |
25 | 32 |
26 internal::DiscardableMemoryManager manager; | 33 static internal::DiscardableMemoryManager* New(void* instance) { |
| 34 return new (instance) internal::DiscardableMemoryManager( |
| 35 kMachMemoryLimit, kMachMemoryLimit, TimeDelta::Max()); |
| 36 } |
| 37 static void Delete(internal::DiscardableMemoryManager* instance) { |
| 38 instance->~DiscardableMemoryManager(); |
| 39 } |
27 }; | 40 }; |
28 LazyInstance<SharedState>::Leaky g_shared_state = LAZY_INSTANCE_INITIALIZER; | 41 |
| 42 LazyInstance<internal::DiscardableMemoryManager, |
| 43 DiscardableMemoryManagerLazyInstanceTraits> |
| 44 g_manager = LAZY_INSTANCE_INITIALIZER; |
29 | 45 |
30 // The VM subsystem allows tagging of memory and 240-255 is reserved for | 46 // The VM subsystem allows tagging of memory and 240-255 is reserved for |
31 // application use (see mach/vm_statistics.h). Pick 252 (after chromium's atomic | 47 // application use (see mach/vm_statistics.h). Pick 252 (after chromium's atomic |
32 // weight of ~52). | 48 // weight of ~52). |
33 const int kDiscardableMemoryTag = VM_MAKE_TAG(252); | 49 const int kDiscardableMemoryTag = VM_MAKE_TAG(252); |
34 | 50 |
35 } // namespace | 51 } // namespace |
36 | 52 |
37 namespace internal { | 53 namespace internal { |
38 | 54 |
39 DiscardableMemoryMach::DiscardableMemoryMach(size_t bytes) | 55 DiscardableMemoryMach::DiscardableMemoryMach(size_t bytes) |
40 : memory_(0, 0), bytes_(mach_vm_round_page(bytes)), is_locked_(false) { | 56 : memory_(0, 0), bytes_(mach_vm_round_page(bytes)), is_locked_(false) { |
41 g_shared_state.Pointer()->manager.Register(this, bytes); | 57 g_manager.Pointer()->Register(this, bytes); |
42 } | 58 } |
43 | 59 |
44 DiscardableMemoryMach::~DiscardableMemoryMach() { | 60 DiscardableMemoryMach::~DiscardableMemoryMach() { |
45 if (is_locked_) | 61 if (is_locked_) |
46 Unlock(); | 62 Unlock(); |
47 g_shared_state.Pointer()->manager.Unregister(this); | 63 g_manager.Pointer()->Unregister(this); |
48 } | 64 } |
49 | 65 |
50 // static | 66 // static |
51 void DiscardableMemoryMach::PurgeForTesting() { | 67 void DiscardableMemoryMach::PurgeForTesting() { |
52 int state = 0; | 68 int state = 0; |
53 vm_purgable_control(mach_task_self(), 0, VM_PURGABLE_PURGE_ALL, &state); | 69 vm_purgable_control(mach_task_self(), 0, VM_PURGABLE_PURGE_ALL, &state); |
54 } | 70 } |
55 | 71 |
56 bool DiscardableMemoryMach::Initialize() { | 72 bool DiscardableMemoryMach::Initialize() { |
57 return Lock() != DISCARDABLE_MEMORY_LOCK_STATUS_FAILED; | 73 return Lock() != DISCARDABLE_MEMORY_LOCK_STATUS_FAILED; |
58 } | 74 } |
59 | 75 |
60 DiscardableMemoryLockStatus DiscardableMemoryMach::Lock() { | 76 DiscardableMemoryLockStatus DiscardableMemoryMach::Lock() { |
61 DCHECK(!is_locked_); | 77 DCHECK(!is_locked_); |
62 | 78 |
63 bool purged = false; | 79 bool purged = false; |
64 if (!g_shared_state.Pointer()->manager.AcquireLock(this, &purged)) | 80 if (!g_manager.Pointer()->AcquireLock(this, &purged)) |
65 return DISCARDABLE_MEMORY_LOCK_STATUS_FAILED; | 81 return DISCARDABLE_MEMORY_LOCK_STATUS_FAILED; |
66 | 82 |
67 is_locked_ = true; | 83 is_locked_ = true; |
68 return purged ? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED | 84 return purged ? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED |
69 : DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS; | 85 : DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS; |
70 } | 86 } |
71 | 87 |
72 void DiscardableMemoryMach::Unlock() { | 88 void DiscardableMemoryMach::Unlock() { |
73 DCHECK(is_locked_); | 89 DCHECK(is_locked_); |
74 g_shared_state.Pointer()->manager.ReleaseLock(this); | 90 g_manager.Pointer()->ReleaseLock(this); |
75 is_locked_ = false; | 91 is_locked_ = false; |
76 } | 92 } |
77 | 93 |
78 void* DiscardableMemoryMach::Memory() const { | 94 void* DiscardableMemoryMach::Memory() const { |
79 DCHECK(is_locked_); | 95 DCHECK(is_locked_); |
80 return reinterpret_cast<void*>(memory_.address()); | 96 return reinterpret_cast<void*>(memory_.address()); |
81 } | 97 } |
82 | 98 |
83 bool DiscardableMemoryMach::AllocateAndAcquireLock() { | 99 bool DiscardableMemoryMach::AllocateAndAcquireLock() { |
84 kern_return_t ret; | 100 kern_return_t ret; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 MACH_DCHECK(ret == KERN_SUCCESS, ret) << "vm_protect"; | 149 MACH_DCHECK(ret == KERN_SUCCESS, ret) << "vm_protect"; |
134 #endif | 150 #endif |
135 } | 151 } |
136 | 152 |
137 void DiscardableMemoryMach::Purge() { | 153 void DiscardableMemoryMach::Purge() { |
138 memory_.reset(); | 154 memory_.reset(); |
139 } | 155 } |
140 | 156 |
141 } // namespace internal | 157 } // namespace internal |
142 } // namespace base | 158 } // namespace base |
OLD | NEW |