OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/child/child_discardable_shared_memory_manager.h" | 5 #include "content/child/child_discardable_shared_memory_manager.h" |
6 | 6 |
7 #include "base/memory/discardable_shared_memory.h" | 7 #include "base/memory/discardable_shared_memory.h" |
| 8 #include "base/process/process_metrics.h" |
8 #include "content/child/child_thread.h" | 9 #include "content/child/child_thread.h" |
9 #include "content/common/child_process_messages.h" | 10 #include "content/common/child_process_messages.h" |
10 | 11 |
11 namespace content { | 12 namespace content { |
| 13 namespace { |
| 14 |
| 15 // Default allocation size. |
| 16 const size_t kAllocationSize = 4 * 1024 * 1024; |
| 17 |
| 18 class DiscardableMemoryShmemChunkImpl |
| 19 : public base::DiscardableMemoryShmemChunk { |
| 20 public: |
| 21 DiscardableMemoryShmemChunkImpl( |
| 22 ChildDiscardableSharedMemoryManager* manager, |
| 23 scoped_ptr<DiscardableSharedMemoryHeap::Span> span) |
| 24 : manager_(manager), span_(span.Pass()) {} |
| 25 ~DiscardableMemoryShmemChunkImpl() override { |
| 26 manager_->ReleaseSpan(span_.Pass()); |
| 27 } |
| 28 |
| 29 // Overridden from DiscardableMemoryShmemChunk: |
| 30 bool Lock() override { return manager_->LockSpan(span_.get()); } |
| 31 void Unlock() override { manager_->UnlockSpan(span_.get()); } |
| 32 void* Memory() const override { |
| 33 return reinterpret_cast<void*>(span_->start() * base::GetPageSize()); |
| 34 } |
| 35 bool IsMemoryResident() const override { |
| 36 return manager_->IsSpanResident(span_.get()); |
| 37 } |
| 38 |
| 39 private: |
| 40 ChildDiscardableSharedMemoryManager* manager_; |
| 41 scoped_ptr<DiscardableSharedMemoryHeap::Span> span_; |
| 42 |
| 43 DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryShmemChunkImpl); |
| 44 }; |
| 45 |
| 46 } // namespace |
12 | 47 |
13 ChildDiscardableSharedMemoryManager::ChildDiscardableSharedMemoryManager( | 48 ChildDiscardableSharedMemoryManager::ChildDiscardableSharedMemoryManager( |
14 ThreadSafeSender* sender) | 49 ThreadSafeSender* sender) |
15 : sender_(sender) { | 50 : heap_(base::GetPageSize()), sender_(sender) { |
16 } | 51 } |
17 | 52 |
18 ChildDiscardableSharedMemoryManager::~ChildDiscardableSharedMemoryManager() { | 53 ChildDiscardableSharedMemoryManager::~ChildDiscardableSharedMemoryManager() { |
19 } | 54 } |
20 | 55 |
| 56 scoped_ptr<base::DiscardableMemoryShmemChunk> |
| 57 ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory( |
| 58 size_t size) { |
| 59 base::AutoLock lock(lock_); |
| 60 |
| 61 DCHECK_NE(size, 0u); |
| 62 |
| 63 // Round up to multiple of page size. |
| 64 size_t pages = (size + base::GetPageSize() - 1) / base::GetPageSize(); |
| 65 |
| 66 for (;;) { |
| 67 // Search free list for available space. |
| 68 scoped_ptr<DiscardableSharedMemoryHeap::Span> free_span = |
| 69 heap_.SearchFreeList(pages); |
| 70 if (!free_span.get()) |
| 71 break; |
| 72 |
| 73 // Attempt to lock |free_span|. Delete span and search free list again |
| 74 // if locking failed. |
| 75 if (!free_span->shared_memory()->Lock( |
| 76 free_span->start() * base::GetPageSize() - |
| 77 reinterpret_cast<size_t>(free_span->shared_memory()->memory()), |
| 78 free_span->length() * base::GetPageSize())) { |
| 79 heap_.DeleteSpan(free_span.Pass()); |
| 80 continue; |
| 81 } |
| 82 |
| 83 return make_scoped_ptr( |
| 84 new DiscardableMemoryShmemChunkImpl(this, free_span.Pass())); |
| 85 } |
| 86 |
| 87 size_t pages_to_allocate = |
| 88 std::max(kAllocationSize / base::GetPageSize(), pages); |
| 89 size_t allocation_size_in_bytes = pages_to_allocate * base::GetPageSize(); |
| 90 |
| 91 // Ask parent process to allocate a new discardable shared memory segment. |
| 92 scoped_ptr<base::DiscardableSharedMemory> shared_memory( |
| 93 AllocateLockedDiscardableSharedMemory(allocation_size_in_bytes)); |
| 94 |
| 95 // Create span for allocated memory. |
| 96 scoped_ptr<DiscardableSharedMemoryHeap::Span> new_span( |
| 97 heap_.Grow(shared_memory.Pass(), allocation_size_in_bytes)); |
| 98 |
| 99 // Unlock and insert any left over memory into free list. |
| 100 if (pages < pages_to_allocate) { |
| 101 scoped_ptr<DiscardableSharedMemoryHeap::Span> leftover = |
| 102 heap_.Split(new_span.get(), pages); |
| 103 leftover->shared_memory()->Unlock( |
| 104 leftover->start() * base::GetPageSize() - |
| 105 reinterpret_cast<size_t>(leftover->shared_memory()->memory()), |
| 106 leftover->length() * base::GetPageSize()); |
| 107 heap_.MergeIntoFreeList(leftover.Pass()); |
| 108 } |
| 109 |
| 110 return make_scoped_ptr( |
| 111 new DiscardableMemoryShmemChunkImpl(this, new_span.Pass())); |
| 112 } |
| 113 |
| 114 bool ChildDiscardableSharedMemoryManager::LockSpan( |
| 115 DiscardableSharedMemoryHeap::Span* span) { |
| 116 base::AutoLock lock(lock_); |
| 117 return span->shared_memory()->Lock( |
| 118 span->start() * base::GetPageSize() - |
| 119 reinterpret_cast<size_t>(span->shared_memory()->memory()), |
| 120 span->length() * base::GetPageSize()); |
| 121 } |
| 122 |
| 123 void ChildDiscardableSharedMemoryManager::UnlockSpan( |
| 124 DiscardableSharedMemoryHeap::Span* span) { |
| 125 base::AutoLock lock(lock_); |
| 126 return span->shared_memory()->Unlock( |
| 127 span->start() * base::GetPageSize() - |
| 128 reinterpret_cast<size_t>(span->shared_memory()->memory()), |
| 129 span->length() * base::GetPageSize()); |
| 130 } |
| 131 |
| 132 bool ChildDiscardableSharedMemoryManager::IsSpanResident( |
| 133 DiscardableSharedMemoryHeap::Span* span) const { |
| 134 base::AutoLock lock(lock_); |
| 135 return span->shared_memory()->IsMemoryResident(); |
| 136 } |
| 137 |
| 138 void ChildDiscardableSharedMemoryManager::ReleaseSpan( |
| 139 scoped_ptr<DiscardableSharedMemoryHeap::Span> span) { |
| 140 base::AutoLock lock(lock_); |
| 141 |
| 142 // Limit free list to spans less or equal to kAllocationSize. |
| 143 if (span->length() * base::GetPageSize() > kAllocationSize) { |
| 144 heap_.DeleteSpan(span.Pass()); |
| 145 return; |
| 146 } |
| 147 |
| 148 heap_.MergeIntoFreeList(span.Pass()); |
| 149 } |
| 150 |
21 scoped_ptr<base::DiscardableSharedMemory> | 151 scoped_ptr<base::DiscardableSharedMemory> |
22 ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory( | 152 ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory( |
23 size_t size) { | 153 size_t size) { |
24 TRACE_EVENT1("renderer", | 154 TRACE_EVENT1("renderer", |
25 "ChildDiscardableSharedMemoryManager::" | 155 "ChildDiscardableSharedMemoryManager::" |
26 "AllocateLockedDiscardableSharedMemory", | 156 "AllocateLockedDiscardableSharedMemory", |
27 "size", | 157 "size", |
28 size); | 158 size); |
29 | 159 |
30 base::SharedMemoryHandle handle = base::SharedMemory::NULLHandle(); | 160 base::SharedMemoryHandle handle = base::SharedMemory::NULLHandle(); |
31 sender_->Send( | 161 sender_->Send( |
32 new ChildProcessHostMsg_SyncAllocateLockedDiscardableSharedMemory( | 162 new ChildProcessHostMsg_SyncAllocateLockedDiscardableSharedMemory( |
33 size, &handle)); | 163 size, &handle)); |
34 scoped_ptr<base::DiscardableSharedMemory> memory( | 164 scoped_ptr<base::DiscardableSharedMemory> memory( |
35 new base::DiscardableSharedMemory(handle)); | 165 new base::DiscardableSharedMemory(handle)); |
36 CHECK(memory->Map(size)); | 166 CHECK(memory->Map(size)); |
37 return memory.Pass(); | 167 return memory.Pass(); |
38 } | 168 } |
39 | 169 |
40 } // namespace content | 170 } // namespace content |
OLD | NEW |