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..4e6e53aa1ad85c04aeaf34888b1317156a353a60 100644 |
--- a/content/common/host_discardable_shared_memory_manager.cc |
+++ b/content/common/host_discardable_shared_memory_manager.cc |
@@ -28,9 +28,8 @@ const int kEnforceMemoryPolicyDelayMs = 1000; |
} // namespace |
HostDiscardableSharedMemoryManager::MemorySegment::MemorySegment( |
- linked_ptr<base::DiscardableSharedMemory> memory, |
- base::ProcessHandle process_handle) |
- : memory(memory), process_handle(process_handle) { |
+ scoped_ptr<base::DiscardableSharedMemory> memory) |
+ : memory_(memory.Pass()) { |
} |
HostDiscardableSharedMemoryManager::MemorySegment::~MemorySegment() { |
@@ -71,6 +70,7 @@ void HostDiscardableSharedMemoryManager:: |
AllocateLockedDiscardableSharedMemoryForChild( |
base::ProcessHandle process_handle, |
size_t size, |
+ DiscardableSharedMemoryId id, |
base::SharedMemoryHandle* shared_memory_handle) { |
// TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466405 |
// is fixed. |
@@ -79,6 +79,14 @@ void HostDiscardableSharedMemoryManager:: |
"466405 AllocateLockedDiscardableSharedMemoryForChild::Start")); |
base::AutoLock lock(lock_); |
+ // Make sure |id| is not already in use. |
+ MemorySegmentMap& process_segments = processes_[process_handle]; |
+ if (process_segments.find(id) != process_segments.end()) { |
+ LOG(ERROR) << "Invalid discardable shared memory ID"; |
+ *shared_memory_handle = base::SharedMemory::NULLHandle(); |
+ return; |
+ } |
+ |
// Memory usage must be reduced to prevent the addition of |size| from |
// taking usage above the limit. Usage should be reduced to 0 in cases |
// where |size| is greater than the limit. |
@@ -104,7 +112,7 @@ void HostDiscardableSharedMemoryManager:: |
tracked_objects::ScopedTracker tracking_profile3( |
FROM_HERE_WITH_EXPLICIT_FUNCTION( |
"466405 AllocateLockedDiscardableSharedMemoryForChild::NewMemory")); |
- linked_ptr<base::DiscardableSharedMemory> memory( |
+ scoped_ptr<base::DiscardableSharedMemory> memory( |
new base::DiscardableSharedMemory); |
if (!memory->CreateAndMap(size)) { |
*shared_memory_handle = base::SharedMemory::NULLHandle(); |
@@ -140,7 +148,9 @@ void HostDiscardableSharedMemoryManager:: |
bytes_allocated_ = checked_bytes_allocated.ValueOrDie(); |
BytesAllocatedChanged(bytes_allocated_); |
- segments_.push_back(MemorySegment(memory, process_handle)); |
+ scoped_refptr<MemorySegment> segment(new MemorySegment(memory.Pass())); |
+ process_segments[id] = segment.get(); |
+ segments_.push_back(segment.get()); |
std::push_heap(segments_.begin(), segments_.end(), CompareMemoryUsageTime); |
// TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466405 |
@@ -154,30 +164,45 @@ void HostDiscardableSharedMemoryManager:: |
ScheduleEnforceMemoryPolicy(); |
} |
-void HostDiscardableSharedMemoryManager::ProcessRemoved( |
+void HostDiscardableSharedMemoryManager::ChildDeletedDiscardableSharedMemory( |
+ DiscardableSharedMemoryId id, |
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; |
+ MemorySegmentMap& process_segments = processes_[process_handle]; |
- 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; |
+ MemorySegmentMap::iterator segment_it = process_segments.find(id); |
+ if (segment_it == process_segments.end()) { |
+ LOG(ERROR) << "Invalid discardable shared memory ID"; |
+ return; |
} |
- if (bytes_allocated_ != bytes_allocated_before_purging) |
+ size_t bytes_allocated_before_releasing_memory = bytes_allocated_; |
+ |
+ ReleaseMemory(segment_it->second->memory()); |
+ |
+ process_segments.erase(segment_it); |
+ |
+ if (bytes_allocated_ != bytes_allocated_before_releasing_memory) |
+ BytesAllocatedChanged(bytes_allocated_); |
+} |
+ |
+void HostDiscardableSharedMemoryManager::ProcessRemoved( |
+ base::ProcessHandle process_handle) { |
+ base::AutoLock lock(lock_); |
+ |
+ ProcessMap::iterator process_it = processes_.find(process_handle); |
+ if (process_it == processes_.end()) |
+ return; |
+ |
+ size_t bytes_allocated_before_releasing_memory = bytes_allocated_; |
+ |
+ for (auto& segment_it : process_it->second) |
+ ReleaseMemory(segment_it.second->memory()); |
+ |
+ processes_.erase(process_it); |
+ |
+ if (bytes_allocated_ != bytes_allocated_before_releasing_memory) |
BytesAllocatedChanged(bytes_allocated_); |
} |
@@ -195,6 +220,12 @@ void HostDiscardableSharedMemoryManager::EnforceMemoryPolicy() { |
ReduceMemoryUsageUntilWithinMemoryLimit(); |
} |
+size_t HostDiscardableSharedMemoryManager::GetBytesAllocated() { |
+ base::AutoLock lock(lock_); |
+ |
+ return bytes_allocated_; |
+} |
+ |
void HostDiscardableSharedMemoryManager::OnMemoryPressure( |
base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) { |
base::AutoLock lock(lock_); |
@@ -215,6 +246,8 @@ void HostDiscardableSharedMemoryManager::OnMemoryPressure( |
void |
HostDiscardableSharedMemoryManager::ReduceMemoryUsageUntilWithinMemoryLimit() { |
+ lock_.AssertAcquired(); |
+ |
if (bytes_allocated_ <= memory_limit_) |
return; |
@@ -243,11 +276,11 @@ void HostDiscardableSharedMemoryManager::ReduceMemoryUsageUntilWithinLimit( |
break; |
// Stop eviction attempts when the LRU segment is currently in use. |
- if (segments_.front().memory->last_known_usage() >= current_time) |
+ if (segments_.front()->memory()->last_known_usage() >= current_time) |
break; |
std::pop_heap(segments_.begin(), segments_.end(), CompareMemoryUsageTime); |
- MemorySegment segment = segments_.back(); |
+ scoped_refptr<MemorySegment> segment = segments_.back(); |
segments_.pop_back(); |
// Attempt to purge and truncate LRU segment. When successful, as much |
@@ -255,16 +288,14 @@ void HostDiscardableSharedMemoryManager::ReduceMemoryUsageUntilWithinLimit( |
// released depends on the platform. The child process should perform |
// periodic cleanup to ensure that all memory is release within a |
// reasonable amount of time. |
- if (segment.memory->PurgeAndTruncate(current_time)) { |
- size_t size = segment.memory->mapped_size(); |
- DCHECK_GE(bytes_allocated_, size); |
- bytes_allocated_ -= size; |
+ if (segment->memory()->PurgeAndTruncate(current_time)) { |
+ ReleaseMemory(segment->memory()); |
continue; |
} |
// Add memory segment (with updated usage timestamp) back on heap after |
// failed attempt to purge it. |
- segments_.push_back(segment); |
+ segments_.push_back(segment.get()); |
std::push_heap(segments_.begin(), segments_.end(), CompareMemoryUsageTime); |
} |
@@ -272,6 +303,23 @@ void HostDiscardableSharedMemoryManager::ReduceMemoryUsageUntilWithinLimit( |
BytesAllocatedChanged(bytes_allocated_); |
} |
+void HostDiscardableSharedMemoryManager::ReleaseMemory( |
+ base::DiscardableSharedMemory* memory) { |
+ lock_.AssertAcquired(); |
+ |
+ size_t size = memory->mapped_size(); |
+ DCHECK_GE(bytes_allocated_, size); |
+ 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 |segments| 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. |
+ memory->Close(); |
+} |
+ |
void HostDiscardableSharedMemoryManager::BytesAllocatedChanged( |
size_t new_bytes_allocated) const { |
TRACE_COUNTER_ID1("renderer_host", "TotalDiscardableMemoryUsage", this, |