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_shmem.h" | 5 #include "base/memory/discardable_memory_shmem.h" |
6 | 6 |
7 #include "base/lazy_instance.h" | 7 #include "base/lazy_instance.h" |
8 #include "base/memory/discardable_memory_shmem_allocator.h" | 8 #include "base/memory/discardable_memory_shmem_allocator.h" |
9 #include "base/memory/discardable_shared_memory.h" | |
10 | 9 |
11 namespace base { | 10 namespace base { |
12 namespace { | |
13 | |
14 // Have the DiscardableMemoryManager trigger in-process eviction | |
15 // when address space usage gets too high (e.g. 512 MBytes). | |
16 const size_t kMemoryLimit = 512 * 1024 * 1024; | |
17 | |
18 // internal::DiscardableMemoryManager has an explicit constructor that takes | |
19 // a number of memory limit parameters. The LeakyLazyInstanceTraits doesn't | |
20 // handle the case. Thus, we need our own class here. | |
21 struct DiscardableMemoryManagerLazyInstanceTraits { | |
22 // Leaky as discardable memory clients can use this after the exit handler | |
23 // has been called. | |
24 static const bool kRegisterOnExit = false; | |
25 #ifndef NDEBUG | |
26 static const bool kAllowedToAccessOnNonjoinableThread = true; | |
27 #endif | |
28 | |
29 static internal::DiscardableMemoryManager* New(void* instance) { | |
30 return new (instance) internal::DiscardableMemoryManager( | |
31 kMemoryLimit, kMemoryLimit, TimeDelta::Max()); | |
32 } | |
33 static void Delete(internal::DiscardableMemoryManager* instance) { | |
34 instance->~DiscardableMemoryManager(); | |
35 } | |
36 }; | |
37 | |
38 LazyInstance<internal::DiscardableMemoryManager, | |
39 DiscardableMemoryManagerLazyInstanceTraits> g_manager = | |
40 LAZY_INSTANCE_INITIALIZER; | |
41 | |
42 } // namespace | |
43 | |
44 namespace internal { | 11 namespace internal { |
45 | 12 |
46 DiscardableMemoryShmem::DiscardableMemoryShmem(size_t bytes) | 13 DiscardableMemoryShmem::DiscardableMemoryShmem(size_t bytes) |
47 : bytes_(bytes), is_locked_(false) { | 14 : bytes_(bytes), is_locked_(false) { |
48 g_manager.Pointer()->Register(this, bytes); | |
49 } | 15 } |
50 | 16 |
51 DiscardableMemoryShmem::~DiscardableMemoryShmem() { | 17 DiscardableMemoryShmem::~DiscardableMemoryShmem() { |
52 if (is_locked_) | 18 if (is_locked_) |
53 Unlock(); | 19 Unlock(); |
54 g_manager.Pointer()->Unregister(this); | |
55 } | |
56 | |
57 // static | |
58 void DiscardableMemoryShmem::ReleaseFreeMemory() { | |
59 g_manager.Pointer()->ReleaseFreeMemory(); | |
60 } | |
61 | |
62 // static | |
63 void DiscardableMemoryShmem::PurgeForTesting() { | |
64 g_manager.Pointer()->PurgeAll(); | |
65 } | 20 } |
66 | 21 |
67 bool DiscardableMemoryShmem::Initialize() { | 22 bool DiscardableMemoryShmem::Initialize() { |
68 return Lock() != DISCARDABLE_MEMORY_LOCK_STATUS_FAILED; | 23 return Lock() != DISCARDABLE_MEMORY_LOCK_STATUS_FAILED; |
69 } | 24 } |
70 | 25 |
71 DiscardableMemoryLockStatus DiscardableMemoryShmem::Lock() { | 26 DiscardableMemoryLockStatus DiscardableMemoryShmem::Lock() { |
72 DCHECK(!is_locked_); | 27 DCHECK(!is_locked_); |
73 | 28 |
74 bool purged = false; | 29 if (chunk_ && chunk_->Lock()) { |
75 if (!g_manager.Pointer()->AcquireLock(this, &purged)) | 30 is_locked_ = true; |
| 31 return DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS; |
| 32 } |
| 33 |
| 34 chunk_ = DiscardableMemoryShmemAllocator::GetInstance() |
| 35 ->AllocateLockedDiscardableMemory(bytes_); |
| 36 if (!chunk_) |
76 return DISCARDABLE_MEMORY_LOCK_STATUS_FAILED; | 37 return DISCARDABLE_MEMORY_LOCK_STATUS_FAILED; |
77 | 38 |
78 is_locked_ = true; | 39 is_locked_ = true; |
79 return purged ? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED | 40 return DISCARDABLE_MEMORY_LOCK_STATUS_PURGED; |
80 : DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS; | |
81 } | 41 } |
82 | 42 |
83 void DiscardableMemoryShmem::Unlock() { | 43 void DiscardableMemoryShmem::Unlock() { |
84 DCHECK(is_locked_); | 44 DCHECK(is_locked_); |
85 g_manager.Pointer()->ReleaseLock(this); | 45 DCHECK(chunk_); |
| 46 chunk_->Unlock(); |
86 is_locked_ = false; | 47 is_locked_ = false; |
87 } | 48 } |
88 | 49 |
89 void* DiscardableMemoryShmem::Memory() const { | 50 void* DiscardableMemoryShmem::Memory() const { |
90 DCHECK(is_locked_); | 51 DCHECK(is_locked_); |
91 DCHECK(chunk_); | 52 DCHECK(chunk_); |
92 return chunk_->Memory(); | 53 return chunk_->Memory(); |
93 } | 54 } |
94 | 55 |
95 bool DiscardableMemoryShmem::AllocateAndAcquireLock() { | |
96 if (chunk_ && chunk_->Lock()) | |
97 return true; | |
98 | |
99 chunk_ = DiscardableMemoryShmemAllocator::GetInstance() | |
100 ->AllocateLockedDiscardableMemory(bytes_); | |
101 DCHECK(chunk_); | |
102 return false; | |
103 } | |
104 | |
105 void DiscardableMemoryShmem::ReleaseLock() { | |
106 chunk_->Unlock(); | |
107 } | |
108 | |
109 void DiscardableMemoryShmem::Purge() { | |
110 DCHECK(!is_locked_); | |
111 chunk_.reset(); | |
112 } | |
113 | |
114 bool DiscardableMemoryShmem::IsMemoryResident() const { | |
115 return chunk_->IsMemoryResident(); | |
116 } | |
117 | |
118 } // namespace internal | 56 } // namespace internal |
119 } // namespace base | 57 } // namespace base |
OLD | NEW |