Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: base/memory/discardable_memory_android.cc

Issue 114923005: base: Discardable memory types. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: address review feedback Created 6 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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_android.h" 5 #include "base/memory/discardable_memory_android.h"
6 6
7 #include <sys/mman.h> 7 #include <sys/mman.h>
8 #include <sys/resource.h> 8 #include <sys/resource.h>
9 #include <sys/time.h> 9 #include <sys/time.h>
10 #include <unistd.h> 10 #include <unistd.h>
11 11
12 #include <limits> 12 #include <limits>
13 13
14 #include "base/android/sys_utils.h" 14 #include "base/android/sys_utils.h"
15 #include "base/basictypes.h" 15 #include "base/basictypes.h"
16 #include "base/compiler_specific.h" 16 #include "base/compiler_specific.h"
17 #include "base/file_util.h" 17 #include "base/file_util.h"
18 #include "base/lazy_instance.h" 18 #include "base/lazy_instance.h"
19 #include "base/logging.h" 19 #include "base/logging.h"
20 #include "base/memory/discardable_memory.h"
21 #include "base/memory/discardable_memory_allocator_android.h" 20 #include "base/memory/discardable_memory_allocator_android.h"
21 #include "base/memory/discardable_memory_emulated.h"
22 #include "base/synchronization/lock.h" 22 #include "base/synchronization/lock.h"
23 #include "third_party/ashmem/ashmem.h" 23 #include "third_party/ashmem/ashmem.h"
24 24
25 namespace base { 25 namespace base {
26 namespace { 26 namespace {
27 27
28 const size_t kPageSize = 4096; 28 const size_t kPageSize = 4096;
29 29
30 const char kAshmemAllocatorName[] = "DiscardableMemoryAllocator"; 30 const char kAshmemAllocatorName[] = "DiscardableMemoryAllocator";
31 31
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 size_(size) { 90 size_(size) {
91 DCHECK_GE(fd_, 0); 91 DCHECK_GE(fd_, 0);
92 DCHECK(memory_); 92 DCHECK(memory_);
93 } 93 }
94 94
95 virtual ~DiscardableMemoryAndroidSimple() { 95 virtual ~DiscardableMemoryAndroidSimple() {
96 internal::CloseAshmemRegion(fd_, size_, memory_); 96 internal::CloseAshmemRegion(fd_, size_, memory_);
97 } 97 }
98 98
99 // DiscardableMemory: 99 // DiscardableMemory:
100 virtual LockDiscardableMemoryStatus Lock() OVERRIDE { 100 virtual DiscardableMemoryLockStatus Lock() OVERRIDE {
101 return internal::LockAshmemRegion(fd_, 0, size_, memory_); 101 return internal::LockAshmemRegion(fd_, 0, size_, memory_);
102 } 102 }
103 103
104 virtual void Unlock() OVERRIDE { 104 virtual void Unlock() OVERRIDE {
105 internal::UnlockAshmemRegion(fd_, 0, size_, memory_); 105 internal::UnlockAshmemRegion(fd_, 0, size_, memory_);
106 } 106 }
107 107
108 virtual void* Memory() const OVERRIDE { 108 virtual void* Memory() const OVERRIDE {
109 return memory_; 109 return memory_;
110 } 110 }
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 AutoLock lock(g_context.Get().lock); 180 AutoLock lock(g_context.Get().lock);
181 g_context.Get().decrement_ashmem_fd_count(); 181 g_context.Get().decrement_ashmem_fd_count();
182 if (munmap(address, size) == -1) { 182 if (munmap(address, size) == -1) {
183 DPLOG(ERROR) << "Failed to unmap memory."; 183 DPLOG(ERROR) << "Failed to unmap memory.";
184 close(fd); 184 close(fd);
185 return false; 185 return false;
186 } 186 }
187 return close(fd) == 0; 187 return close(fd) == 0;
188 } 188 }
189 189
190 LockDiscardableMemoryStatus LockAshmemRegion(int fd, 190 DiscardableMemoryLockStatus LockAshmemRegion(int fd,
191 size_t off, 191 size_t off,
192 size_t size, 192 size_t size,
193 const void* address) { 193 const void* address) {
194 const int result = ashmem_pin_region(fd, off, size); 194 const int result = ashmem_pin_region(fd, off, size);
195 DCHECK_EQ(0, mprotect(address, size, PROT_READ | PROT_WRITE)); 195 DCHECK_EQ(0, mprotect(address, size, PROT_READ | PROT_WRITE));
196 return result == ASHMEM_WAS_PURGED ? 196 return result == ASHMEM_WAS_PURGED ? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED
197 DISCARDABLE_MEMORY_PURGED : DISCARDABLE_MEMORY_SUCCESS; 197 : DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS;
198 } 198 }
199 199
200 bool UnlockAshmemRegion(int fd, size_t off, size_t size, const void* address) { 200 bool UnlockAshmemRegion(int fd, size_t off, size_t size, const void* address) {
201 const int failed = ashmem_unpin_region(fd, off, size); 201 const int failed = ashmem_unpin_region(fd, off, size);
202 if (failed) 202 if (failed)
203 DLOG(ERROR) << "Failed to unpin memory."; 203 DLOG(ERROR) << "Failed to unpin memory.";
204 // This allows us to catch accesses to unlocked memory. 204 // This allows us to catch accesses to unlocked memory.
205 DCHECK_EQ(0, mprotect(address, size, PROT_NONE)); 205 DCHECK_EQ(0, mprotect(address, size, PROT_NONE));
206 return !failed; 206 return !failed;
207 } 207 }
208 208
209 } // namespace internal 209 } // namespace internal
210 210
211 // static 211 // static
212 bool DiscardableMemory::SupportedNatively() { 212 void DiscardableMemory::GetSupportedTypes(
213 return true; 213 std::vector<DiscardableMemoryType>* types) {
214 const DiscardableMemoryType supported_types[] = {
215 DISCARDABLE_MEMORY_TYPE_ANDROID,
216 DISCARDABLE_MEMORY_TYPE_EMULATED
217 };
218 types->assign(supported_types, supported_types + arraysize(supported_types));
214 } 219 }
215 220
216 // Allocation can happen in two ways: 221 // Allocation can happen in two ways:
217 // - Each client-requested allocation is backed by an individual ashmem region. 222 // - Each client-requested allocation is backed by an individual ashmem region.
218 // This allows deleting ashmem regions individually by closing the ashmem file 223 // This allows deleting ashmem regions individually by closing the ashmem file
219 // descriptor. This is the default path that is taken when file descriptor usage 224 // descriptor. This is the default path that is taken when file descriptor usage
220 // allows us to do so or when the allocation size would require and entire 225 // allows us to do so or when the allocation size would require and entire
221 // ashmem region. 226 // ashmem region.
222 // - Allocations are performed by the global allocator when file descriptor 227 // - Allocations are performed by the global allocator when file descriptor
223 // usage gets too high. This still allows unpinning but does not allow deleting 228 // usage gets too high. This still allows unpinning but does not allow deleting
224 // (i.e. releasing the physical pages backing) individual regions. 229 // (i.e. releasing the physical pages backing) individual regions.
225 // 230 //
226 // TODO(pliard): consider tuning the size threshold used below. For instance we 231 // TODO(pliard): consider tuning the size threshold used below. For instance we
227 // might want to make it a fraction of kMinAshmemRegionSize and also 232 // might want to make it a fraction of kMinAshmemRegionSize and also
228 // systematically have small allocations go through the allocator to let big 233 // systematically have small allocations go through the allocator to let big
229 // allocations systematically go through individual ashmem regions. 234 // allocations systematically go through individual ashmem regions.
230 // 235 //
231 // static 236 // static
232 scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemory( 237 scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemory(
233 size_t size) { 238 DiscardableMemoryType type, size_t size) {
234 if (!CheckSizeCanBeAlignedToNextPage(size)) 239 switch (type) {
235 return scoped_ptr<DiscardableMemory>(); 240 case DISCARDABLE_MEMORY_TYPE_NONE:
236 // Pinning & unpinning works with page granularity therefore align the size 241 case DISCARDABLE_MEMORY_TYPE_MAC:
237 // upfront. 242 return scoped_ptr<DiscardableMemory>();
238 const size_t aligned_size = internal::AlignToNextPage(size); 243 case DISCARDABLE_MEMORY_TYPE_ANDROID: {
239 // Note that the following code is slightly racy. The worst that can happen in 244 if (!CheckSizeCanBeAlignedToNextPage(size))
240 // practice though is taking the wrong decision (e.g. using the allocator 245 return scoped_ptr<DiscardableMemory>();
241 // rather than DiscardableMemoryAndroidSimple). Moreover keeping the lock 246 // Pinning & unpinning works with page granularity therefore align the
242 // acquired for the whole allocation would cause a deadlock when the allocator 247 // size upfront.
243 // tries to create an ashmem region. 248 const size_t aligned_size = internal::AlignToNextPage(size);
244 GlobalContext* const global_context = g_context.Pointer(); 249 // Note that the following code is slightly racy. The worst that can
245 if (GetCurrentNumberOfAshmemFDs() < 0.9 * global_context->ashmem_fd_limit) { 250 // happen in practice though is taking the wrong decision (e.g. using
246 int fd; 251 // the allocator rather than DiscardableMemoryAndroidSimple). Moreover
247 void* address; 252 // keeping the lock acquired for the whole allocation would cause a
248 if (internal::CreateAshmemRegion("", aligned_size, &fd, &address)) { 253 // deadlock when the allocator tries to create an ashmem region.
249 return scoped_ptr<DiscardableMemory>( 254 GlobalContext* const global_context = g_context.Pointer();
250 new DiscardableMemoryAndroidSimple(fd, address, aligned_size)); 255 if (GetCurrentNumberOfAshmemFDs() <
256 0.9 * global_context->ashmem_fd_limit) {
257 int fd;
258 void* address;
259 if (internal::CreateAshmemRegion("", aligned_size, &fd, &address)) {
260 return scoped_ptr<DiscardableMemory>(
261 new DiscardableMemoryAndroidSimple(fd, address, aligned_size));
262 }
263 }
264 return global_context->allocator.Allocate(size);
265 }
266 case DISCARDABLE_MEMORY_TYPE_EMULATED: {
267 scoped_ptr<internal::DiscardableMemoryEmulated> memory(
268 new internal::DiscardableMemoryEmulated(size));
269 if (!memory->Initialize())
270 return scoped_ptr<DiscardableMemory>();
271
272 return memory.PassAs<DiscardableMemory>();
251 } 273 }
252 } 274 }
253 return global_context->allocator.Allocate(size); 275
276 NOTREACHED();
277 return scoped_ptr<DiscardableMemory>();
254 } 278 }
255 279
256 // static 280 // static
257 bool DiscardableMemory::PurgeForTestingSupported() { 281 bool DiscardableMemory::PurgeForTestingSupported() {
258 return false; 282 return false;
259 } 283 }
260 284
261 // static 285 // static
262 void DiscardableMemory::PurgeForTesting() { 286 void DiscardableMemory::PurgeForTesting() {
263 NOTIMPLEMENTED(); 287 NOTIMPLEMENTED();
264 } 288 }
265 289
266 } // namespace base 290 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698