| Index: mojo/services/html_viewer/discardable_memory_allocator.cc
|
| diff --git a/mojo/services/html_viewer/discardable_memory_allocator.cc b/mojo/services/html_viewer/discardable_memory_allocator.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..569c3d0d3908cd8f9ed5c86da4a69d721a0d8d36
|
| --- /dev/null
|
| +++ b/mojo/services/html_viewer/discardable_memory_allocator.cc
|
| @@ -0,0 +1,151 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "mojo/services/html_viewer/discardable_memory_allocator.h"
|
| +
|
| +#include "base/memory/discardable_memory.h"
|
| +#include "base/memory/weak_ptr.h"
|
| +#include "base/stl_util.h"
|
| +
|
| +namespace html_viewer {
|
| +
|
| +// Represents an actual memory chunk. This is an object owned by
|
| +// DiscardableMemoryAllocator. DiscardableMemoryChunkImpl are passed to the
|
| +// rest of the program, and access this memory through a weak ptr.
|
| +class DiscardableMemoryAllocator::OwnedMemoryChunk {
|
| + public:
|
| + OwnedMemoryChunk(size_t size, DiscardableMemoryAllocator* allocator)
|
| + : is_locked_(true),
|
| + size_(size),
|
| + memory_(new uint8_t[size]),
|
| + allocator_(allocator),
|
| + weak_factory_(this) {}
|
| + ~OwnedMemoryChunk() {}
|
| +
|
| + void Lock() {
|
| + DCHECK(!is_locked_);
|
| + is_locked_ = true;
|
| + allocator_->NotifyLocked(unlocked_position_);
|
| + }
|
| +
|
| + void Unlock() {
|
| + DCHECK(is_locked_);
|
| + is_locked_ = false;
|
| + unlocked_position_ = allocator_->NotifyUnlocked(this);
|
| + }
|
| +
|
| + bool is_locked() const { return is_locked_; }
|
| + size_t size() const { return size_; }
|
| + void* Memory() const {
|
| + DCHECK(is_locked_);
|
| + return memory_.get();
|
| + }
|
| +
|
| + base::WeakPtr<OwnedMemoryChunk> GetWeakPtr() {
|
| + return weak_factory_.GetWeakPtr();
|
| + }
|
| +
|
| + private:
|
| + bool is_locked_;
|
| + size_t size_;
|
| + scoped_ptr<uint8_t[]> memory_;
|
| + DiscardableMemoryAllocator* allocator_;
|
| +
|
| + std::list<OwnedMemoryChunk*>::iterator unlocked_position_;
|
| +
|
| + base::WeakPtrFactory<OwnedMemoryChunk> weak_factory_;
|
| +
|
| + DISALLOW_IMPLICIT_CONSTRUCTORS(OwnedMemoryChunk);
|
| +};
|
| +
|
| +namespace {
|
| +
|
| +// Interface to the rest of the program. These objects are owned outside of the
|
| +// allocator and wrap a weak ptr.
|
| +class DiscardableMemoryChunkImpl : public base::DiscardableMemory {
|
| + public:
|
| + explicit DiscardableMemoryChunkImpl(
|
| + base::WeakPtr<DiscardableMemoryAllocator::OwnedMemoryChunk> chunk)
|
| + : memory_chunk_(chunk) {}
|
| + ~DiscardableMemoryChunkImpl() override {
|
| + // Either the memory chunk is invalid (because the backing has gone away),
|
| + // or the memory chunk is unlocked (because leaving the chunk locked once
|
| + // we deallocate means the chunk will never get cleaned up).
|
| + DCHECK(!memory_chunk_ || !memory_chunk_->is_locked());
|
| + }
|
| +
|
| + // Overridden from DiscardableMemoryChunk:
|
| + bool Lock() override {
|
| + if (!memory_chunk_)
|
| + return false;
|
| +
|
| + memory_chunk_->Lock();
|
| + return true;
|
| + }
|
| +
|
| + void Unlock() override {
|
| + DCHECK(memory_chunk_);
|
| + memory_chunk_->Unlock();
|
| + }
|
| +
|
| + void* Memory() const override {
|
| + if (memory_chunk_)
|
| + return memory_chunk_->Memory();
|
| + return nullptr;
|
| + }
|
| +
|
| + private:
|
| + base::WeakPtr<DiscardableMemoryAllocator::OwnedMemoryChunk> memory_chunk_;
|
| +
|
| + DISALLOW_IMPLICIT_CONSTRUCTORS(DiscardableMemoryChunkImpl);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +DiscardableMemoryAllocator::DiscardableMemoryAllocator(
|
| + size_t desired_max_memory)
|
| + : desired_max_memory_(desired_max_memory),
|
| + total_live_memory_(0u),
|
| + locked_chunks_(0) {
|
| +}
|
| +
|
| +DiscardableMemoryAllocator::~DiscardableMemoryAllocator() {
|
| + DCHECK_EQ(0, locked_chunks_);
|
| + STLDeleteElements(&live_unlocked_chunks_);
|
| +}
|
| +
|
| +scoped_ptr<base::DiscardableMemory>
|
| +DiscardableMemoryAllocator::AllocateLockedDiscardableMemory(size_t size) {
|
| + OwnedMemoryChunk* chunk = new OwnedMemoryChunk(size, this);
|
| + total_live_memory_ += size;
|
| + locked_chunks_++;
|
| +
|
| + // Go through the list of unlocked live chunks starting from the least
|
| + // recently used, freeing as many as we can until we get our size under the
|
| + // desired maximum.
|
| + auto it = live_unlocked_chunks_.begin();
|
| + while (total_live_memory_ > desired_max_memory_ &&
|
| + it != live_unlocked_chunks_.end()) {
|
| + total_live_memory_ -= (*it)->size();
|
| + delete *it;
|
| + it = live_unlocked_chunks_.erase(it);
|
| + }
|
| +
|
| + return make_scoped_ptr(new DiscardableMemoryChunkImpl(chunk->GetWeakPtr()));
|
| +}
|
| +
|
| +std::list<DiscardableMemoryAllocator::OwnedMemoryChunk*>::iterator
|
| +DiscardableMemoryAllocator::NotifyUnlocked(
|
| + DiscardableMemoryAllocator::OwnedMemoryChunk* chunk) {
|
| + locked_chunks_--;
|
| + return live_unlocked_chunks_.insert(live_unlocked_chunks_.end(), chunk);
|
| +}
|
| +
|
| +void DiscardableMemoryAllocator::NotifyLocked(
|
| + std::list<OwnedMemoryChunk*>::iterator it) {
|
| + locked_chunks_++;
|
| + live_unlocked_chunks_.erase(it);
|
| +}
|
| +
|
| +} // namespace html_viewer
|
|
|