| Index: content/renderer/render_process_discardable_memory_provider.cc
|
| diff --git a/content/renderer/render_process_discardable_memory_provider.cc b/content/renderer/render_process_discardable_memory_provider.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d284d0ff7bc789da2aca78a1239fabbbed469701
|
| --- /dev/null
|
| +++ b/content/renderer/render_process_discardable_memory_provider.cc
|
| @@ -0,0 +1,148 @@
|
| +// Copyright (c) 2012 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 "content/renderer/render_process_discardable_memory_provider.h"
|
| +
|
| +namespace content {
|
| +
|
| +namespace {
|
| +
|
| +class EmulatedDiscardableMemory : public base::DiscardableMemory {
|
| + public:
|
| + EmulatedDiscardableMemory(RenderProcessDiscardableMemoryProvider* provider)
|
| + : provider_(provider) {
|
| + }
|
| +
|
| + virtual ~EmulatedDiscardableMemory() {
|
| + }
|
| +
|
| + virtual bool InitializeAndLock(size_t size) OVERRIDE {
|
| + if (provider_->Register(this, size))
|
| + return Lock() != base::DISCARDABLE_MEMORY_FAILED;
|
| + return false;
|
| + }
|
| +
|
| + virtual base::LockDiscardableMemoryStatus Lock() OVERRIDE {
|
| + return provider_->Lock(this);
|
| + }
|
| +
|
| + virtual void Unlock() OVERRIDE {
|
| + provider_->Unlock(this);
|
| + }
|
| +
|
| + virtual void* Memory() const OVERRIDE {
|
| + return provider_->Memory(this);
|
| + }
|
| +
|
| + private:
|
| + RenderProcessDiscardableMemoryProvider* provider_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(EmulatedDiscardableMemory);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +RenderProcessDiscardableMemoryProvider::
|
| + RenderProcessDiscardableMemoryProvider()
|
| + : visible_(false) {
|
| +}
|
| +
|
| +RenderProcessDiscardableMemoryProvider::
|
| + ~RenderProcessDiscardableMemoryProvider() {
|
| + AllocationMap::iterator it = allocations_.begin();
|
| + for (; it != allocations_.end(); ++it)
|
| + if (it->second.memory != NULL)
|
| + free(it->second.memory);
|
| +}
|
| +
|
| +void RenderProcessDiscardableMemoryProvider::RenderProcessVisibilityChanged(
|
| + bool visible) {
|
| + visible_ = visible;
|
| + EnforcePolicy();
|
| +}
|
| +
|
| +bool RenderProcessDiscardableMemoryProvider::Register(
|
| + const base::DiscardableMemory* discardable, size_t size) {
|
| + Unregister(discardable);
|
| + AllocatedMemory allocation = { NULL, false, size };
|
| + allocation.memory = malloc(size * sizeof(char));
|
| + if (allocation.memory == NULL)
|
| + return false;
|
| + allocations_[discardable] = allocation;
|
| + return true;
|
| +}
|
| +
|
| +void RenderProcessDiscardableMemoryProvider::Unregister(
|
| + const base::DiscardableMemory* discardable) {
|
| + AllocationMap::iterator it = allocations_.find(discardable);
|
| + if (it == allocations_.end())
|
| + return;
|
| + DCHECK(!it->second.locked);
|
| + if (it->second.memory != NULL)
|
| + free(it->second.memory);
|
| + allocations_.erase(it);
|
| +}
|
| +
|
| +base::LockDiscardableMemoryStatus RenderProcessDiscardableMemoryProvider::Lock(
|
| + const base::DiscardableMemory* discardable) {
|
| + AllocationMap::iterator it = allocations_.find(discardable);
|
| + if (it == allocations_.end())
|
| + return base::DISCARDABLE_MEMORY_FAILED;
|
| +
|
| + it->second.locked = true;
|
| + if (it->second.memory != NULL)
|
| + return base::DISCARDABLE_MEMORY_SUCCESS;
|
| +
|
| + it->second.memory = malloc(it->second.size * sizeof(char));
|
| + return base::DISCARDABLE_MEMORY_PURGED;
|
| +}
|
| +
|
| +void RenderProcessDiscardableMemoryProvider::Unlock(
|
| + const base::DiscardableMemory* discardable) {
|
| + AllocationMap::iterator it = allocations_.find(discardable);
|
| + if (it == allocations_.end())
|
| + return;
|
| + it->second.locked = false;
|
| +}
|
| +
|
| +void* RenderProcessDiscardableMemoryProvider::Memory(
|
| + const base::DiscardableMemory* discardable) const {
|
| + AllocationMap::const_iterator it = allocations_.find(discardable);
|
| + DCHECK(it->second.locked);
|
| + if (it == allocations_.end())
|
| + return NULL;
|
| + return it->second.memory;
|
| +}
|
| +
|
| +base::DiscardableMemory* RenderProcessDiscardableMemoryProvider::
|
| + CreateDiscardableMemory() {
|
| + return new EmulatedDiscardableMemory(this);
|
| +}
|
| +
|
| +bool RenderProcessDiscardableMemoryProvider::PurgeForTestingSupported() const {
|
| + return true;
|
| +}
|
| +
|
| +void RenderProcessDiscardableMemoryProvider::PurgeForTesting() {
|
| + Purge();
|
| +}
|
| +
|
| +void RenderProcessDiscardableMemoryProvider::Purge() {
|
| + AllocationMap::iterator it = allocations_.begin();
|
| + for (; it != allocations_.end(); ++it) {
|
| + if (it->second.memory != NULL && !it->second.locked) {
|
| + free(it->second.memory);
|
| + it->second.memory = NULL;
|
| + }
|
| + }
|
| +}
|
| +
|
| +// We could be smarter here and use a MRU scheme and memory limits. Instead,
|
| +// we'll just purge everything when the process is no longer visible.
|
| +void RenderProcessDiscardableMemoryProvider::EnforcePolicy() {
|
| + if (!visible_)
|
| + Purge();
|
| +}
|
| +
|
| +} // namespace content
|
|
|