| Index: base/memory/discardable_memory_allocation_ashmem_factory.cc
|
| diff --git a/base/memory/discardable_memory_allocator_android.cc b/base/memory/discardable_memory_allocation_ashmem_factory.cc
|
| similarity index 82%
|
| copy from base/memory/discardable_memory_allocator_android.cc
|
| copy to base/memory/discardable_memory_allocation_ashmem_factory.cc
|
| index 1588317ef646b30a1e1a7f825e5414bb1a645886..b0e946303bdac84e65a0413ccf083e2fe6689303 100644
|
| --- a/base/memory/discardable_memory_allocator_android.cc
|
| +++ b/base/memory/discardable_memory_allocation_ashmem_factory.cc
|
| @@ -2,7 +2,7 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include "base/memory/discardable_memory_allocator_android.h"
|
| +#include "base/memory/discardable_memory_allocation_ashmem_factory.h"
|
|
|
| #include <sys/mman.h>
|
| #include <unistd.h>
|
| @@ -20,20 +20,19 @@
|
| #include "base/logging.h"
|
| #include "base/memory/discardable_memory.h"
|
| #include "base/memory/scoped_vector.h"
|
| -#include "base/synchronization/lock.h"
|
| #include "base/threading/thread_checker.h"
|
| #include "third_party/ashmem/ashmem.h"
|
|
|
| -// The allocator consists of three parts (classes):
|
| -// - DiscardableMemoryAllocator: entry point of all allocations (through its
|
| -// Allocate() method) that are dispatched to the AshmemRegion instances (which
|
| -// it owns).
|
| +// This file consists of the following parts:
|
| +// - DiscardableMemoryAllocationAshmemFactory: entry point of all allocations
|
| +// (through its Create() method) that are dispatched to the AshmemRegion
|
| +// instances (which it owns).
|
| // - AshmemRegion: manages allocations and destructions inside a single large
|
| // (e.g. 32 MBytes) ashmem region.
|
| -// - DiscardableAshmemChunk: class implementing the DiscardableMemory interface
|
| -// whose instances are returned to the client. DiscardableAshmemChunk lets the
|
| -// client seamlessly operate on a subrange of the ashmem region managed by
|
| -// AshmemRegion.
|
| +// - DiscardableAshmemChunk: class implementing the DiscardableMemoryAllocation
|
| +// interface whose instances are returned to the client. DiscardableAshmemChunk
|
| +// lets the client seamlessly operate on a subrange of the ashmem region managed
|
| +// by AshmemRegion.
|
|
|
| namespace base {
|
| namespace {
|
| @@ -102,14 +101,10 @@ bool CloseAshmemRegion(int fd, size_t size, void* address) {
|
| return close(fd) == 0;
|
| }
|
|
|
| -DiscardableMemoryLockStatus LockAshmemRegion(int fd,
|
| - size_t off,
|
| - size_t size,
|
| - const void* address) {
|
| +bool LockAshmemRegion(int fd, size_t off, size_t size, const void* address) {
|
| const int result = ashmem_pin_region(fd, off, size);
|
| DCHECK_EQ(0, mprotect(address, size, PROT_READ | PROT_WRITE));
|
| - return result == ASHMEM_WAS_PURGED ? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED
|
| - : DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS;
|
| + return result != ASHMEM_WAS_PURGED;
|
| }
|
|
|
| bool UnlockAshmemRegion(int fd, size_t off, size_t size, const void* address) {
|
| @@ -125,8 +120,8 @@ bool UnlockAshmemRegion(int fd, size_t off, size_t size, const void* address) {
|
|
|
| namespace internal {
|
|
|
| -class DiscardableMemoryAllocator::DiscardableAshmemChunk
|
| - : public DiscardableMemory {
|
| +class DiscardableMemoryAllocationAshmemFactory::DiscardableAshmemChunk
|
| + : public DiscardableMemoryAllocation {
|
| public:
|
| // Note that |ashmem_region| must outlive |this|.
|
| DiscardableAshmemChunk(AshmemRegion* ashmem_region,
|
| @@ -146,8 +141,8 @@ class DiscardableMemoryAllocator::DiscardableAshmemChunk
|
| // AshmemRegion.
|
| virtual ~DiscardableAshmemChunk();
|
|
|
| - // DiscardableMemory:
|
| - virtual DiscardableMemoryLockStatus Lock() OVERRIDE {
|
| + // DiscardableMemoryAllocation:
|
| + virtual bool Lock() OVERRIDE {
|
| DCHECK(!locked_);
|
| locked_ = true;
|
| return LockAshmemRegion(fd_, offset_, size_, address_);
|
| @@ -159,7 +154,7 @@ class DiscardableMemoryAllocator::DiscardableAshmemChunk
|
| UnlockAshmemRegion(fd_, offset_, size_, address_);
|
| }
|
|
|
| - virtual void* Memory() const OVERRIDE {
|
| + virtual void* Memory() OVERRIDE {
|
| return address_;
|
| }
|
|
|
| @@ -174,13 +169,13 @@ class DiscardableMemoryAllocator::DiscardableAshmemChunk
|
| DISALLOW_COPY_AND_ASSIGN(DiscardableAshmemChunk);
|
| };
|
|
|
| -class DiscardableMemoryAllocator::AshmemRegion {
|
| +class DiscardableMemoryAllocationAshmemFactory::AshmemRegion {
|
| public:
|
| // Note that |allocator| must outlive |this|.
|
| static scoped_ptr<AshmemRegion> Create(
|
| size_t size,
|
| const std::string& name,
|
| - DiscardableMemoryAllocator* allocator) {
|
| + DiscardableMemoryAllocationAshmemFactory* allocator) {
|
| DCHECK_EQ(size, AlignToNextPage(size));
|
| int fd;
|
| void* base;
|
| @@ -195,21 +190,20 @@ class DiscardableMemoryAllocator::AshmemRegion {
|
| DCHECK(!highest_allocated_chunk_);
|
| }
|
|
|
| - // Returns a new instance of DiscardableMemory whose size is greater or equal
|
| - // than |actual_size| (which is expected to be greater or equal than
|
| + // Returns a new instance of DiscardableMemoryAllocation whose size is greater
|
| + // or equal than |actual_size| (which is expected to be greater or equal than
|
| // |client_requested_size|).
|
| // Allocation works as follows:
|
| // 1) Reuse a previously freed chunk and return it if it succeeded. See
|
| - // ReuseFreeChunk_Locked() below for more information.
|
| + // ReuseFreeChunk() below for more information.
|
| // 2) If no free chunk could be reused and the region is not big enough for
|
| // the requested size then NULL is returned.
|
| // 3) If there is enough room in the ashmem region then a new chunk is
|
| // returned. This new chunk starts at |offset_| which is the end of the
|
| // previously highest chunk in the region.
|
| - scoped_ptr<DiscardableMemory> Allocate_Locked(size_t client_requested_size,
|
| - size_t actual_size) {
|
| + scoped_ptr<DiscardableMemoryAllocation> Allocate(size_t client_requested_size,
|
| + size_t actual_size) {
|
| DCHECK_LE(client_requested_size, actual_size);
|
| - allocator_->lock_.AssertAcquired();
|
|
|
| // Check that the |highest_allocated_chunk_| field doesn't contain a stale
|
| // pointer. It should point to either a free chunk or a used chunk.
|
| @@ -219,14 +213,14 @@ class DiscardableMemoryAllocator::AshmemRegion {
|
| used_to_previous_chunk_map_.find(highest_allocated_chunk_) !=
|
| used_to_previous_chunk_map_.end());
|
|
|
| - scoped_ptr<DiscardableMemory> memory = ReuseFreeChunk_Locked(
|
| + scoped_ptr<DiscardableMemoryAllocation> memory = ReuseFreeChunk(
|
| client_requested_size, actual_size);
|
| if (memory)
|
| return memory.Pass();
|
|
|
| if (size_ - offset_ < actual_size) {
|
| // This region does not have enough space left to hold the requested size.
|
| - return scoped_ptr<DiscardableMemory>();
|
| + return scoped_ptr<DiscardableMemoryAllocation>();
|
| }
|
|
|
| void* const address = static_cast<char*>(base_) + offset_;
|
| @@ -242,8 +236,7 @@ class DiscardableMemoryAllocator::AshmemRegion {
|
| }
|
|
|
| void OnChunkDeletion(void* chunk, size_t size) {
|
| - AutoLock auto_lock(allocator_->lock_);
|
| - MergeAndAddFreeChunk_Locked(chunk, size);
|
| + MergeAndAddFreeChunk(chunk, size);
|
| // Note that |this| might be deleted beyond this point.
|
| }
|
|
|
| @@ -279,7 +272,7 @@ class DiscardableMemoryAllocator::AshmemRegion {
|
| AshmemRegion(int fd,
|
| size_t size,
|
| void* base,
|
| - DiscardableMemoryAllocator* allocator)
|
| + DiscardableMemoryAllocationAshmemFactory* allocator)
|
| : fd_(fd),
|
| size_(size),
|
| base_(base),
|
| @@ -293,14 +286,13 @@ class DiscardableMemoryAllocator::AshmemRegion {
|
| }
|
|
|
| // Tries to reuse a previously freed chunk by doing a closest size match.
|
| - scoped_ptr<DiscardableMemory> ReuseFreeChunk_Locked(
|
| + scoped_ptr<DiscardableMemoryAllocation> ReuseFreeChunk(
|
| size_t client_requested_size,
|
| size_t actual_size) {
|
| - allocator_->lock_.AssertAcquired();
|
| - const FreeChunk reused_chunk = RemoveFreeChunkFromIterator_Locked(
|
| + const FreeChunk reused_chunk = RemoveFreeChunkFromIterator(
|
| free_chunks_.lower_bound(FreeChunk(actual_size)));
|
| if (reused_chunk.is_null())
|
| - return scoped_ptr<DiscardableMemory>();
|
| + return scoped_ptr<DiscardableMemoryAllocation>();
|
|
|
| used_to_previous_chunk_map_.insert(
|
| std::make_pair(reused_chunk.start, reused_chunk.previous_chunk));
|
| @@ -329,14 +321,14 @@ class DiscardableMemoryAllocator::AshmemRegion {
|
| const size_t new_chunk_size = reused_chunk.size - actual_size;
|
| // Note that merging is not needed here since there can't be contiguous
|
| // free chunks at this point.
|
| - AddFreeChunk_Locked(
|
| - FreeChunk(reused_chunk.start, new_chunk_start, new_chunk_size));
|
| + AddFreeChunk(
|
| + FreeChunk(reused_chunk.start, new_chunk_start,new_chunk_size));
|
| }
|
|
|
| const size_t offset =
|
| static_cast<char*>(reused_chunk.start) - static_cast<char*>(base_);
|
| LockAshmemRegion(fd_, offset, reused_chunk_size, reused_chunk.start);
|
| - scoped_ptr<DiscardableMemory> memory(
|
| + scoped_ptr<DiscardableMemoryAllocation> memory(
|
| new DiscardableAshmemChunk(this, fd_, reused_chunk.start, offset,
|
| reused_chunk_size));
|
| return memory.Pass();
|
| @@ -354,8 +346,7 @@ class DiscardableMemoryAllocator::AshmemRegion {
|
| // change in versions of kernel >=3.5 though. The fact that free chunks are
|
| // not immediately released is the reason why we are trying to minimize
|
| // fragmentation in order not to cause "artificial" memory pressure.
|
| - void MergeAndAddFreeChunk_Locked(void* chunk, size_t size) {
|
| - allocator_->lock_.AssertAcquired();
|
| + void MergeAndAddFreeChunk(void* chunk, size_t size) {
|
| size_t new_free_chunk_size = size;
|
| // Merge with the previous chunk.
|
| void* first_free_chunk = chunk;
|
| @@ -367,7 +358,7 @@ class DiscardableMemoryAllocator::AshmemRegion {
|
| used_to_previous_chunk_map_.erase(previous_chunk_it);
|
|
|
| if (previous_chunk) {
|
| - const FreeChunk free_chunk = RemoveFreeChunk_Locked(previous_chunk);
|
| + const FreeChunk free_chunk = RemoveFreeChunk(previous_chunk);
|
| if (!free_chunk.is_null()) {
|
| new_free_chunk_size += free_chunk.size;
|
| first_free_chunk = previous_chunk;
|
| @@ -382,7 +373,7 @@ class DiscardableMemoryAllocator::AshmemRegion {
|
|
|
| // Merge with the next chunk if free and present.
|
| void* next_chunk = static_cast<char*>(chunk) + size;
|
| - const FreeChunk next_free_chunk = RemoveFreeChunk_Locked(next_chunk);
|
| + const FreeChunk next_free_chunk = RemoveFreeChunk(next_chunk);
|
| if (!next_free_chunk.is_null()) {
|
| new_free_chunk_size += next_free_chunk.size;
|
| if (next_free_chunk.start == highest_allocated_chunk_)
|
| @@ -396,7 +387,7 @@ class DiscardableMemoryAllocator::AshmemRegion {
|
| const bool whole_ashmem_region_is_free =
|
| used_to_previous_chunk_map_.empty();
|
| if (!whole_ashmem_region_is_free) {
|
| - AddFreeChunk_Locked(
|
| + AddFreeChunk(
|
| FreeChunk(previous_chunk, first_free_chunk, new_free_chunk_size));
|
| return;
|
| }
|
| @@ -408,11 +399,10 @@ class DiscardableMemoryAllocator::AshmemRegion {
|
| DCHECK(address_to_free_chunk_map_.empty());
|
| DCHECK(used_to_previous_chunk_map_.empty());
|
| highest_allocated_chunk_ = NULL;
|
| - allocator_->DeleteAshmemRegion_Locked(this); // Deletes |this|.
|
| + allocator_->DeleteAshmemRegion(this); // Deletes |this|.
|
| }
|
|
|
| - void AddFreeChunk_Locked(const FreeChunk& free_chunk) {
|
| - allocator_->lock_.AssertAcquired();
|
| + void AddFreeChunk(const FreeChunk& free_chunk) {
|
| const std::multiset<FreeChunk>::iterator it = free_chunks_.insert(
|
| free_chunk);
|
| address_to_free_chunk_map_.insert(std::make_pair(free_chunk.start, it));
|
| @@ -429,20 +419,18 @@ class DiscardableMemoryAllocator::AshmemRegion {
|
| // Finds and removes the free chunk, if any, whose start address is
|
| // |chunk_start|. Returns a copy of the unlinked free chunk or a free chunk
|
| // whose content is null if it was not found.
|
| - FreeChunk RemoveFreeChunk_Locked(void* chunk_start) {
|
| - allocator_->lock_.AssertAcquired();
|
| + FreeChunk RemoveFreeChunk(void* chunk_start) {
|
| const hash_map<
|
| void*, std::multiset<FreeChunk>::iterator>::iterator it =
|
| address_to_free_chunk_map_.find(chunk_start);
|
| if (it == address_to_free_chunk_map_.end())
|
| return FreeChunk();
|
| - return RemoveFreeChunkFromIterator_Locked(it->second);
|
| + return RemoveFreeChunkFromIterator(it->second);
|
| }
|
|
|
| // Same as above but takes an iterator in.
|
| - FreeChunk RemoveFreeChunkFromIterator_Locked(
|
| + FreeChunk RemoveFreeChunkFromIterator(
|
| std::multiset<FreeChunk>::iterator free_chunk_it) {
|
| - allocator_->lock_.AssertAcquired();
|
| if (free_chunk_it == free_chunks_.end())
|
| return FreeChunk();
|
| DCHECK(free_chunk_it != free_chunks_.end());
|
| @@ -455,7 +443,7 @@ class DiscardableMemoryAllocator::AshmemRegion {
|
| const int fd_;
|
| const size_t size_;
|
| void* const base_;
|
| - DiscardableMemoryAllocator* const allocator_;
|
| + DiscardableMemoryAllocationAshmemFactory* const allocator_;
|
| // Points to the chunk with the highest address in the region. This pointer
|
| // needs to be carefully updated when chunks are merged/split.
|
| void* highest_allocated_chunk_;
|
| @@ -479,13 +467,15 @@ class DiscardableMemoryAllocator::AshmemRegion {
|
| DISALLOW_COPY_AND_ASSIGN(AshmemRegion);
|
| };
|
|
|
| -DiscardableMemoryAllocator::DiscardableAshmemChunk::~DiscardableAshmemChunk() {
|
| +DiscardableMemoryAllocationAshmemFactory::DiscardableAshmemChunk::
|
| + ~DiscardableAshmemChunk() {
|
| if (locked_)
|
| UnlockAshmemRegion(fd_, offset_, size_, address_);
|
| ashmem_region_->OnChunkDeletion(address_, size_);
|
| }
|
|
|
| -DiscardableMemoryAllocator::DiscardableMemoryAllocator(
|
| +DiscardableMemoryAllocationAshmemFactory::
|
| + DiscardableMemoryAllocationAshmemFactory(
|
| const std::string& name,
|
| size_t ashmem_region_size)
|
| : name_(name),
|
| @@ -495,26 +485,27 @@ DiscardableMemoryAllocator::DiscardableMemoryAllocator(
|
| DCHECK_GE(ashmem_region_size_, kMinAshmemRegionSize);
|
| }
|
|
|
| -DiscardableMemoryAllocator::~DiscardableMemoryAllocator() {
|
| +DiscardableMemoryAllocationAshmemFactory::
|
| + ~DiscardableMemoryAllocationAshmemFactory() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| DCHECK(ashmem_regions_.empty());
|
| }
|
|
|
| -scoped_ptr<DiscardableMemory> DiscardableMemoryAllocator::Allocate(
|
| +scoped_ptr<DiscardableMemoryAllocation>
|
| +DiscardableMemoryAllocationAshmemFactory::CreateLockedAllocation(
|
| size_t size) {
|
| const size_t aligned_size = AlignToNextPage(size);
|
| if (!aligned_size)
|
| - return scoped_ptr<DiscardableMemory>();
|
| + return scoped_ptr<DiscardableMemoryAllocation>();
|
| // TODO(pliard): make this function less naive by e.g. moving the free chunks
|
| // multiset to the allocator itself in order to decrease even more
|
| // fragmentation/speedup allocation. Note that there should not be more than a
|
| // couple (=5) of AshmemRegion instances in practice though.
|
| - AutoLock auto_lock(lock_);
|
| DCHECK_LE(ashmem_regions_.size(), 5U);
|
| for (ScopedVector<AshmemRegion>::iterator it = ashmem_regions_.begin();
|
| it != ashmem_regions_.end(); ++it) {
|
| - scoped_ptr<DiscardableMemory> memory(
|
| - (*it)->Allocate_Locked(size, aligned_size));
|
| + scoped_ptr<DiscardableMemoryAllocation> memory(
|
| + (*it)->Allocate(size, aligned_size));
|
| if (memory)
|
| return memory.Pass();
|
| }
|
| @@ -531,20 +522,19 @@ scoped_ptr<DiscardableMemory> DiscardableMemoryAllocator::Allocate(
|
| continue;
|
| last_ashmem_region_size_ = region_size;
|
| ashmem_regions_.push_back(new_region.release());
|
| - return ashmem_regions_.back()->Allocate_Locked(size, aligned_size);
|
| + return ashmem_regions_.back()->Allocate(size, aligned_size);
|
| }
|
| // TODO(pliard): consider adding an histogram to see how often this happens.
|
| - return scoped_ptr<DiscardableMemory>();
|
| + return scoped_ptr<DiscardableMemoryAllocation>();
|
| }
|
|
|
| -size_t DiscardableMemoryAllocator::last_ashmem_region_size() const {
|
| - AutoLock auto_lock(lock_);
|
| +size_t
|
| +DiscardableMemoryAllocationAshmemFactory::last_ashmem_region_size() const {
|
| return last_ashmem_region_size_;
|
| }
|
|
|
| -void DiscardableMemoryAllocator::DeleteAshmemRegion_Locked(
|
| +void DiscardableMemoryAllocationAshmemFactory::DeleteAshmemRegion(
|
| AshmemRegion* region) {
|
| - lock_.AssertAcquired();
|
| // Note that there should not be more than a couple of ashmem region instances
|
| // in |ashmem_regions_|.
|
| DCHECK_LE(ashmem_regions_.size(), 5U);
|
|
|