| Index: content/common/host_discardable_shared_memory_manager.cc
|
| diff --git a/content/common/host_discardable_shared_memory_manager.cc b/content/common/host_discardable_shared_memory_manager.cc
|
| index e150fc63dcf00a11da58b0b4ae912f8a94ada2e5..3d2be9d22c1e32bcad935e4cc8694b60e1282df7 100644
|
| --- a/content/common/host_discardable_shared_memory_manager.cc
|
| +++ b/content/common/host_discardable_shared_memory_manager.cc
|
| @@ -18,6 +18,46 @@
|
| namespace content {
|
| namespace {
|
|
|
| +class DiscardableMemoryShmemChunkImpl
|
| + : public base::DiscardableMemoryShmemChunk {
|
| + public:
|
| + explicit DiscardableMemoryShmemChunkImpl(
|
| + scoped_ptr<base::DiscardableSharedMemory> shared_memory)
|
| + : shared_memory_(shared_memory.Pass()), is_locked_(true) {}
|
| + ~DiscardableMemoryShmemChunkImpl() override {
|
| + if (is_locked_)
|
| + shared_memory_->Unlock(0, 0);
|
| + shared_memory_->Purge(base::Time::Now());
|
| + }
|
| +
|
| + // Overridden from base::DiscardableMemoryShmemChunk:
|
| + bool Lock() override {
|
| + DCHECK(!is_locked_);
|
| +
|
| + if (shared_memory_->Lock(0, 0) != base::DiscardableSharedMemory::SUCCESS)
|
| + return false;
|
| +
|
| + is_locked_ = true;
|
| + return true;
|
| + }
|
| + void Unlock() override {
|
| + DCHECK(is_locked_);
|
| +
|
| + shared_memory_->Unlock(0, 0);
|
| + is_locked_ = false;
|
| + }
|
| + void* Memory() const override {
|
| + DCHECK(is_locked_);
|
| + return shared_memory_->memory();
|
| + }
|
| +
|
| + private:
|
| + scoped_ptr<base::DiscardableSharedMemory> shared_memory_;
|
| + bool is_locked_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryShmemChunkImpl);
|
| +};
|
| +
|
| base::LazyInstance<HostDiscardableSharedMemoryManager>
|
| g_discardable_shared_memory_manager = LAZY_INSTANCE_INITIALIZER;
|
|
|
| @@ -61,10 +101,16 @@ HostDiscardableSharedMemoryManager::current() {
|
| scoped_ptr<base::DiscardableMemoryShmemChunk>
|
| HostDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory(
|
| size_t size) {
|
| - // TODO(reveman): Need to implement this for discardable memory support in
|
| - // the browser process.
|
| - NOTIMPLEMENTED();
|
| - return nullptr;
|
| + // Note: Use DiscardableSharedMemoryHeap for in-process allocation
|
| + // of discardable memory if the cost of each allocation is too high.
|
| + base::SharedMemoryHandle handle;
|
| + AllocateLockedDiscardableSharedMemory(base::GetCurrentProcessHandle(), size,
|
| + &handle);
|
| + CHECK(base::SharedMemory::IsHandleValid(handle));
|
| + scoped_ptr<base::DiscardableSharedMemory> memory(
|
| + new base::DiscardableSharedMemory(handle));
|
| + CHECK(memory->Map(size));
|
| + return make_scoped_ptr(new DiscardableMemoryShmemChunkImpl(memory.Pass()));
|
| }
|
|
|
| void HostDiscardableSharedMemoryManager::
|
| @@ -72,11 +118,60 @@ void HostDiscardableSharedMemoryManager::
|
| base::ProcessHandle process_handle,
|
| size_t size,
|
| base::SharedMemoryHandle* shared_memory_handle) {
|
| + AllocateLockedDiscardableSharedMemory(process_handle, size,
|
| + shared_memory_handle);
|
| +}
|
| +
|
| +void HostDiscardableSharedMemoryManager::ProcessRemoved(
|
| + base::ProcessHandle process_handle) {
|
| + base::AutoLock lock(lock_);
|
| +
|
| + size_t bytes_allocated_before_purging = bytes_allocated_;
|
| + for (auto& segment : segments_) {
|
| + // Skip segments that belong to a different process.
|
| + if (segment.process_handle != process_handle)
|
| + continue;
|
| +
|
| + size_t size = segment.memory->mapped_size();
|
| + DCHECK_GE(bytes_allocated_, size);
|
| +
|
| + // This will unmap the memory segment and drop our reference. The result
|
| + // is that the memory will be released to the OS if the child process is
|
| + // no longer referencing it.
|
| + // Note: We intentionally leave the segment in the vector to avoid
|
| + // reconstructing the heap. The element will be removed from the heap
|
| + // when its last usage time is older than all other segments.
|
| + segment.memory->Close();
|
| + bytes_allocated_ -= size;
|
| + }
|
| +
|
| + if (bytes_allocated_ != bytes_allocated_before_purging)
|
| + BytesAllocatedChanged(bytes_allocated_);
|
| +}
|
| +
|
| +void HostDiscardableSharedMemoryManager::SetMemoryLimit(size_t limit) {
|
| + base::AutoLock lock(lock_);
|
| +
|
| + memory_limit_ = limit;
|
| + ReduceMemoryUsageUntilWithinMemoryLimit();
|
| +}
|
| +
|
| +void HostDiscardableSharedMemoryManager::EnforceMemoryPolicy() {
|
| + base::AutoLock lock(lock_);
|
| +
|
| + enforce_memory_policy_pending_ = false;
|
| + ReduceMemoryUsageUntilWithinMemoryLimit();
|
| +}
|
| +
|
| +void HostDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
|
| + base::ProcessHandle process_handle,
|
| + size_t size,
|
| + base::SharedMemoryHandle* shared_memory_handle) {
|
| // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466405
|
| // is fixed.
|
| tracked_objects::ScopedTracker tracking_profile1(
|
| FROM_HERE_WITH_EXPLICIT_FUNCTION(
|
| - "466405 AllocateLockedDiscardableSharedMemoryForChild::Start"));
|
| + "466405 AllocateLockedDiscardableSharedMemory::Start"));
|
| base::AutoLock lock(lock_);
|
|
|
| // Memory usage must be reduced to prevent the addition of |size| from
|
| @@ -94,8 +189,7 @@ void HostDiscardableSharedMemoryManager::
|
| // is fixed.
|
| tracked_objects::ScopedTracker tracking_profile2(
|
| FROM_HERE_WITH_EXPLICIT_FUNCTION(
|
| - "466405 "
|
| - "AllocateLockedDiscardableSharedMemoryForChild::ReduceMemoryUsage"));
|
| + "466405 AllocateLockedDiscardableSharedMemory::ReduceMemoryUsage"));
|
| if (bytes_allocated_ > limit)
|
| ReduceMemoryUsageUntilWithinLimit(limit);
|
|
|
| @@ -103,7 +197,7 @@ void HostDiscardableSharedMemoryManager::
|
| // is fixed.
|
| tracked_objects::ScopedTracker tracking_profile3(
|
| FROM_HERE_WITH_EXPLICIT_FUNCTION(
|
| - "466405 AllocateLockedDiscardableSharedMemoryForChild::NewMemory"));
|
| + "466405 AllocateLockedDiscardableSharedMemory::NewMemory"));
|
| linked_ptr<base::DiscardableSharedMemory> memory(
|
| new base::DiscardableSharedMemory);
|
| if (!memory->CreateAndMap(size)) {
|
| @@ -115,8 +209,7 @@ void HostDiscardableSharedMemoryManager::
|
| // is fixed.
|
| tracked_objects::ScopedTracker tracking_profile4(
|
| FROM_HERE_WITH_EXPLICIT_FUNCTION(
|
| - "466405 "
|
| - "AllocateLockedDiscardableSharedMemoryForChild::ShareToProcess"));
|
| + "466405 AllocateLockedDiscardableSharedMemory::ShareToProcess"));
|
| if (!memory->ShareToProcess(process_handle, shared_memory_handle)) {
|
| LOG(ERROR) << "Cannot share discardable memory segment";
|
| *shared_memory_handle = base::SharedMemory::NULLHandle();
|
| @@ -135,8 +228,7 @@ void HostDiscardableSharedMemoryManager::
|
| tracked_objects::ScopedTracker tracking_profile5(
|
| FROM_HERE_WITH_EXPLICIT_FUNCTION(
|
| "466405 "
|
| - "AllocateLockedDiscardableSharedMemoryForChild::"
|
| - "BytesAllocatedChanged"));
|
| + "AllocateLockedDiscardableSharedMemory::BytesAllocatedChanged"));
|
| bytes_allocated_ = checked_bytes_allocated.ValueOrDie();
|
| BytesAllocatedChanged(bytes_allocated_);
|
|
|
| @@ -148,53 +240,12 @@ void HostDiscardableSharedMemoryManager::
|
| tracked_objects::ScopedTracker tracking_profile6(
|
| FROM_HERE_WITH_EXPLICIT_FUNCTION(
|
| "466405 "
|
| - "AllocateLockedDiscardableSharedMemoryForChild::"
|
| + "AllocateLockedDiscardableSharedMemory::"
|
| "ScheduleEnforceMemoryPolicy"));
|
| if (bytes_allocated_ > memory_limit_)
|
| ScheduleEnforceMemoryPolicy();
|
| }
|
|
|
| -void HostDiscardableSharedMemoryManager::ProcessRemoved(
|
| - base::ProcessHandle process_handle) {
|
| - base::AutoLock lock(lock_);
|
| -
|
| - size_t bytes_allocated_before_purging = bytes_allocated_;
|
| - for (auto& segment : segments_) {
|
| - // Skip segments that belong to a different process.
|
| - if (segment.process_handle != process_handle)
|
| - continue;
|
| -
|
| - size_t size = segment.memory->mapped_size();
|
| - DCHECK_GE(bytes_allocated_, size);
|
| -
|
| - // This will unmap the memory segment and drop our reference. The result
|
| - // is that the memory will be released to the OS if the child process is
|
| - // no longer referencing it.
|
| - // Note: We intentionally leave the segment in the vector to avoid
|
| - // reconstructing the heap. The element will be removed from the heap
|
| - // when its last usage time is older than all other segments.
|
| - segment.memory->Close();
|
| - bytes_allocated_ -= size;
|
| - }
|
| -
|
| - if (bytes_allocated_ != bytes_allocated_before_purging)
|
| - BytesAllocatedChanged(bytes_allocated_);
|
| -}
|
| -
|
| -void HostDiscardableSharedMemoryManager::SetMemoryLimit(size_t limit) {
|
| - base::AutoLock lock(lock_);
|
| -
|
| - memory_limit_ = limit;
|
| - ReduceMemoryUsageUntilWithinMemoryLimit();
|
| -}
|
| -
|
| -void HostDiscardableSharedMemoryManager::EnforceMemoryPolicy() {
|
| - base::AutoLock lock(lock_);
|
| -
|
| - enforce_memory_policy_pending_ = false;
|
| - ReduceMemoryUsageUntilWithinMemoryLimit();
|
| -}
|
| -
|
| void HostDiscardableSharedMemoryManager::OnMemoryPressure(
|
| base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
|
| base::AutoLock lock(lock_);
|
|
|