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
3 // found in the LICENSE file.
5 #include "content/child/child_discardable_shared_memory_manager.h"
7 #include "base/memory/discardable_shared_memory.h"
8 #include "base/process/process_metrics.h"
9 #include "content/child/child_thread.h"
10 #include "content/common/child_process_messages.h"
15 // Default allocation size.
16 const size_t kAllocationSize
= 4 * 1024 * 1024;
18 class DiscardableMemoryShmemChunkImpl
19 : public base::DiscardableMemoryShmemChunk
{
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());
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());
35 bool IsMemoryResident() const override
{
36 return manager_
->IsSpanResident(span_
.get());
40 ChildDiscardableSharedMemoryManager
* manager_
;
41 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span_
;
43 DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryShmemChunkImpl
);
48 ChildDiscardableSharedMemoryManager::ChildDiscardableSharedMemoryManager(
49 ThreadSafeSender
* sender
)
50 : heap_(base::GetPageSize()), sender_(sender
) {
53 ChildDiscardableSharedMemoryManager::~ChildDiscardableSharedMemoryManager() {
56 scoped_ptr
<base::DiscardableMemoryShmemChunk
>
57 ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory(
59 base::AutoLock
lock(lock_
);
63 // Round up to multiple of page size.
64 size_t pages
= (size
+ base::GetPageSize() - 1) / base::GetPageSize();
67 // Search free list for available space.
68 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> free_span
=
69 heap_
.SearchFreeList(pages
);
73 // Attempt to lock |free_span|. Delete span and search free list again
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());
83 return make_scoped_ptr(
84 new DiscardableMemoryShmemChunkImpl(this, free_span
.Pass()));
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();
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
));
95 // Create span for allocated memory.
96 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> new_span(
97 heap_
.Grow(shared_memory
.Pass(), allocation_size_in_bytes
));
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());
110 return make_scoped_ptr(
111 new DiscardableMemoryShmemChunkImpl(this, new_span
.Pass()));
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());
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());
132 bool ChildDiscardableSharedMemoryManager::IsSpanResident(
133 DiscardableSharedMemoryHeap::Span
* span
) const {
134 base::AutoLock
lock(lock_
);
135 return span
->shared_memory()->IsMemoryResident();
138 void ChildDiscardableSharedMemoryManager::ReleaseSpan(
139 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span
) {
140 base::AutoLock
lock(lock_
);
142 // Limit free list to spans less or equal to kAllocationSize.
143 if (span
->length() * base::GetPageSize() > kAllocationSize
) {
144 heap_
.DeleteSpan(span
.Pass());
148 heap_
.MergeIntoFreeList(span
.Pass());
151 scoped_ptr
<base::DiscardableSharedMemory
>
152 ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
154 TRACE_EVENT1("renderer",
155 "ChildDiscardableSharedMemoryManager::"
156 "AllocateLockedDiscardableSharedMemory",
160 base::SharedMemoryHandle handle
= base::SharedMemory::NULLHandle();
162 new ChildProcessHostMsg_SyncAllocateLockedDiscardableSharedMemory(
164 scoped_ptr
<base::DiscardableSharedMemory
> memory(
165 new base::DiscardableSharedMemory(handle
));
166 CHECK(memory
->Map(size
));
167 return memory
.Pass();
170 } // namespace content