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 "components/discardable_memory/service/discardable_shared_memory_manage
r.h" | 5 #include "components/discardable_memory/service/discardable_shared_memory_manage
r.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/atomic_sequence_num.h" | 10 #include "base/atomic_sequence_num.h" |
(...skipping 11 matching lines...) Expand all Loading... |
22 #include "base/strings/string_number_conversions.h" | 22 #include "base/strings/string_number_conversions.h" |
23 #include "base/strings/stringprintf.h" | 23 #include "base/strings/stringprintf.h" |
24 #include "base/sys_info.h" | 24 #include "base/sys_info.h" |
25 #include "base/threading/thread_task_runner_handle.h" | 25 #include "base/threading/thread_task_runner_handle.h" |
26 #include "base/trace_event/memory_allocator_dump.h" | 26 #include "base/trace_event/memory_allocator_dump.h" |
27 #include "base/trace_event/memory_dump_manager.h" | 27 #include "base/trace_event/memory_dump_manager.h" |
28 #include "base/trace_event/process_memory_dump.h" | 28 #include "base/trace_event/process_memory_dump.h" |
29 #include "base/trace_event/trace_event.h" | 29 #include "base/trace_event/trace_event.h" |
30 #include "build/build_config.h" | 30 #include "build/build_config.h" |
31 #include "components/discardable_memory/common/discardable_shared_memory_heap.h" | 31 #include "components/discardable_memory/common/discardable_shared_memory_heap.h" |
32 #include "mojo/public/cpp/bindings/strong_binding.h" | |
33 #include "mojo/public/cpp/system/platform_handle.h" | |
34 | 32 |
35 #if defined(OS_LINUX) | 33 #if defined(OS_LINUX) |
36 #include "base/files/file_path.h" | 34 #include "base/files/file_path.h" |
37 #include "base/files/file_util.h" | 35 #include "base/files/file_util.h" |
38 #include "base/metrics/histogram_macros.h" | 36 #include "base/metrics/histogram_macros.h" |
39 #endif | 37 #endif |
40 | 38 |
41 namespace discardable_memory { | 39 namespace discardable_memory { |
42 namespace { | 40 namespace { |
43 | 41 |
44 const char kSingleProcess[] = "single-process"; | 42 const char kSingleProcess[] = "single-process"; |
45 | 43 |
46 const int kInvalidUniqueClientID = -1; | 44 const int kInvalidUniqueClientID = -1; |
47 | 45 |
48 const uint64_t kBrowserTracingProcessId = std::numeric_limits<uint64_t>::max(); | 46 const uint64_t kBrowserTracingProcessId = std::numeric_limits<uint64_t>::max(); |
49 | 47 |
50 uint64_t ClientProcessUniqueIdToTracingProcessId(int client_id) { | 48 uint64_t ClientProcessUniqueIdToTracingProcessId(int client_id) { |
51 // TODO(penghuang): Move this function to right place. | 49 // TODO(penghuang): Move this function to right place. |
52 // https://crbug.com/661257 | 50 // https://crbug.com/661257 |
53 if (base::CommandLine::ForCurrentProcess()->HasSwitch(kSingleProcess)) | 51 if (base::CommandLine::ForCurrentProcess()->HasSwitch(kSingleProcess)) |
54 return kBrowserTracingProcessId; | 52 return kBrowserTracingProcessId; |
55 // The hash value is incremented so that the tracing id is never equal to | 53 // The hash value is incremented so that the tracing id is never equal to |
56 // MemoryDumpManager::kInvalidTracingProcessId. | 54 // MemoryDumpManager::kInvalidTracingProcessId. |
57 return static_cast<uint64_t>(base::Hash( | 55 return static_cast<uint64_t>(base::Hash( |
58 reinterpret_cast<const char*>(&client_id), sizeof(client_id))) + | 56 reinterpret_cast<const char*>(&client_id), sizeof(client_id))) + |
59 1; | 57 1; |
60 } | 58 } |
61 | 59 |
62 // mojom::DiscardableSharedMemoryManager implementation. It contains the | |
63 // |client_id_| which is not visible to client. We associate allocations with a | |
64 // given mojo instance, so if the instance is closed, we can release the | |
65 // allocations associated with that instance. | |
66 class MojoDiscardableSharedMemoryManagerImpl | |
67 : public mojom::DiscardableSharedMemoryManager { | |
68 public: | |
69 MojoDiscardableSharedMemoryManagerImpl( | |
70 int32_t client_id, | |
71 ::discardable_memory::DiscardableSharedMemoryManager* manager) | |
72 : client_id_(client_id), manager_(manager) {} | |
73 | |
74 ~MojoDiscardableSharedMemoryManagerImpl() override { | |
75 // Remove this client from the |manager_|, so all allocated discardable | |
76 // memory belong to this client will be released. | |
77 manager_->ClientRemoved(client_id_); | |
78 } | |
79 | |
80 // mojom::DiscardableSharedMemoryManager overrides: | |
81 void AllocateLockedDiscardableSharedMemory( | |
82 uint32_t size, | |
83 int32_t id, | |
84 const AllocateLockedDiscardableSharedMemoryCallback& callback) override { | |
85 base::SharedMemoryHandle handle; | |
86 manager_->AllocateLockedDiscardableSharedMemoryForClient(client_id_, size, | |
87 id, &handle); | |
88 mojo::ScopedSharedBufferHandle memory = | |
89 mojo::WrapSharedMemoryHandle(handle, size, false /* read_only */); | |
90 return callback.Run(std::move(memory)); | |
91 } | |
92 | |
93 void DeletedDiscardableSharedMemory(int32_t id) override { | |
94 manager_->ClientDeletedDiscardableSharedMemory(id, client_id_); | |
95 } | |
96 | |
97 private: | |
98 const int32_t client_id_; | |
99 ::discardable_memory::DiscardableSharedMemoryManager* const manager_; | |
100 | |
101 DISALLOW_COPY_AND_ASSIGN(MojoDiscardableSharedMemoryManagerImpl); | |
102 }; | |
103 | |
104 class DiscardableMemoryImpl : public base::DiscardableMemory { | 60 class DiscardableMemoryImpl : public base::DiscardableMemory { |
105 public: | 61 public: |
106 DiscardableMemoryImpl( | 62 DiscardableMemoryImpl( |
107 std::unique_ptr<base::DiscardableSharedMemory> shared_memory, | 63 std::unique_ptr<base::DiscardableSharedMemory> shared_memory, |
108 const base::Closure& deleted_callback) | 64 const base::Closure& deleted_callback) |
109 : shared_memory_(std::move(shared_memory)), | 65 : shared_memory_(std::move(shared_memory)), |
110 deleted_callback_(deleted_callback), | 66 deleted_callback_(deleted_callback), |
111 is_locked_(true) {} | 67 is_locked_(true) {} |
112 | 68 |
113 ~DiscardableMemoryImpl() override { | 69 ~DiscardableMemoryImpl() override { |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 | 173 |
218 } // namespace | 174 } // namespace |
219 | 175 |
220 DiscardableSharedMemoryManager::MemorySegment::MemorySegment( | 176 DiscardableSharedMemoryManager::MemorySegment::MemorySegment( |
221 std::unique_ptr<base::DiscardableSharedMemory> memory) | 177 std::unique_ptr<base::DiscardableSharedMemory> memory) |
222 : memory_(std::move(memory)) {} | 178 : memory_(std::move(memory)) {} |
223 | 179 |
224 DiscardableSharedMemoryManager::MemorySegment::~MemorySegment() {} | 180 DiscardableSharedMemoryManager::MemorySegment::~MemorySegment() {} |
225 | 181 |
226 DiscardableSharedMemoryManager::DiscardableSharedMemoryManager() | 182 DiscardableSharedMemoryManager::DiscardableSharedMemoryManager() |
227 : next_client_id_(1), | 183 : default_memory_limit_(GetDefaultMemoryLimit()), |
228 default_memory_limit_(GetDefaultMemoryLimit()), | |
229 memory_limit_(default_memory_limit_), | 184 memory_limit_(default_memory_limit_), |
230 bytes_allocated_(0), | 185 bytes_allocated_(0), |
231 memory_pressure_listener_(new base::MemoryPressureListener( | 186 memory_pressure_listener_(new base::MemoryPressureListener( |
232 base::Bind(&DiscardableSharedMemoryManager::OnMemoryPressure, | 187 base::Bind(&DiscardableSharedMemoryManager::OnMemoryPressure, |
233 base::Unretained(this)))), | 188 base::Unretained(this)))), |
234 // Current thread might not have a task runner in tests. | 189 // Current thread might not have a task runner in tests. |
235 enforce_memory_policy_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 190 enforce_memory_policy_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
236 enforce_memory_policy_pending_(false), | 191 enforce_memory_policy_pending_(false), |
237 weak_ptr_factory_(this) { | 192 weak_ptr_factory_(this) { |
238 DCHECK_NE(memory_limit_, 0u); | 193 DCHECK_NE(memory_limit_, 0u); |
239 enforce_memory_policy_callback_ = | 194 enforce_memory_policy_callback_ = |
240 base::Bind(&DiscardableSharedMemoryManager::EnforceMemoryPolicy, | 195 base::Bind(&DiscardableSharedMemoryManager::EnforceMemoryPolicy, |
241 weak_ptr_factory_.GetWeakPtr()); | 196 weak_ptr_factory_.GetWeakPtr()); |
242 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( | 197 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( |
243 this, "DiscardableSharedMemoryManager", | 198 this, "DiscardableSharedMemoryManager", |
244 base::ThreadTaskRunnerHandle::Get()); | 199 base::ThreadTaskRunnerHandle::Get()); |
245 base::MemoryCoordinatorClientRegistry::GetInstance()->Register(this); | 200 base::MemoryCoordinatorClientRegistry::GetInstance()->Register(this); |
246 } | 201 } |
247 | 202 |
248 DiscardableSharedMemoryManager::~DiscardableSharedMemoryManager() { | 203 DiscardableSharedMemoryManager::~DiscardableSharedMemoryManager() { |
249 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( | 204 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( |
250 this); | 205 this); |
251 } | 206 } |
252 | 207 |
253 // static | 208 DiscardableSharedMemoryManager* DiscardableSharedMemoryManager::current() { |
254 DiscardableSharedMemoryManager* | |
255 DiscardableSharedMemoryManager::CreateInstance() { | |
256 DCHECK(g_discardable_shared_memory_manager == nullptr); | |
257 return g_discardable_shared_memory_manager.Pointer(); | 209 return g_discardable_shared_memory_manager.Pointer(); |
258 } | 210 } |
259 | 211 |
260 // static | |
261 DiscardableSharedMemoryManager* DiscardableSharedMemoryManager::GetInstance() { | |
262 DCHECK(!(g_discardable_shared_memory_manager == nullptr)); | |
263 return g_discardable_shared_memory_manager.Pointer(); | |
264 } | |
265 | |
266 void DiscardableSharedMemoryManager::Bind( | |
267 mojom::DiscardableSharedMemoryManagerRequest request) { | |
268 mojo::MakeStrongBinding( | |
269 base::MakeUnique<MojoDiscardableSharedMemoryManagerImpl>( | |
270 next_client_id_++, this), | |
271 std::move(request)); | |
272 } | |
273 | |
274 std::unique_ptr<base::DiscardableMemory> | 212 std::unique_ptr<base::DiscardableMemory> |
275 DiscardableSharedMemoryManager::AllocateLockedDiscardableMemory(size_t size) { | 213 DiscardableSharedMemoryManager::AllocateLockedDiscardableMemory(size_t size) { |
276 DCHECK_NE(size, 0u); | 214 DCHECK_NE(size, 0u); |
277 | 215 |
278 int32_t new_id = g_next_discardable_shared_memory_id.GetNext(); | 216 DiscardableSharedMemoryId new_id = |
| 217 g_next_discardable_shared_memory_id.GetNext(); |
| 218 base::ProcessHandle current_process_handle = base::GetCurrentProcessHandle(); |
279 | 219 |
280 // Note: Use DiscardableSharedMemoryHeap for in-process allocation | 220 // Note: Use DiscardableSharedMemoryHeap for in-process allocation |
281 // of discardable memory if the cost of each allocation is too high. | 221 // of discardable memory if the cost of each allocation is too high. |
282 base::SharedMemoryHandle handle; | 222 base::SharedMemoryHandle handle; |
283 AllocateLockedDiscardableSharedMemory(kInvalidUniqueClientID, size, new_id, | 223 AllocateLockedDiscardableSharedMemory( |
284 &handle); | 224 current_process_handle, kInvalidUniqueClientID, size, new_id, &handle); |
285 std::unique_ptr<base::DiscardableSharedMemory> memory( | 225 std::unique_ptr<base::DiscardableSharedMemory> memory( |
286 new base::DiscardableSharedMemory(handle)); | 226 new base::DiscardableSharedMemory(handle)); |
287 if (!memory->Map(size)) | 227 if (!memory->Map(size)) |
288 base::TerminateBecauseOutOfMemory(size); | 228 base::TerminateBecauseOutOfMemory(size); |
289 // Close file descriptor to avoid running out. | 229 // Close file descriptor to avoid running out. |
290 memory->Close(); | 230 memory->Close(); |
291 return base::MakeUnique<DiscardableMemoryImpl>( | 231 return base::MakeUnique<DiscardableMemoryImpl>( |
292 std::move(memory), | 232 std::move(memory), |
293 base::Bind( | 233 base::Bind( |
294 &DiscardableSharedMemoryManager::DeletedDiscardableSharedMemory, | 234 &DiscardableSharedMemoryManager::DeletedDiscardableSharedMemory, |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
361 static_cast<uint64_t>(resident_size)); | 301 static_cast<uint64_t>(resident_size)); |
362 } | 302 } |
363 #endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED) | 303 #endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED) |
364 } | 304 } |
365 } | 305 } |
366 return true; | 306 return true; |
367 } | 307 } |
368 | 308 |
369 void DiscardableSharedMemoryManager:: | 309 void DiscardableSharedMemoryManager:: |
370 AllocateLockedDiscardableSharedMemoryForClient( | 310 AllocateLockedDiscardableSharedMemoryForClient( |
| 311 base::ProcessHandle process_handle, |
371 int client_id, | 312 int client_id, |
372 size_t size, | 313 size_t size, |
373 int32_t id, | 314 DiscardableSharedMemoryId id, |
374 base::SharedMemoryHandle* shared_memory_handle) { | 315 base::SharedMemoryHandle* shared_memory_handle) { |
375 AllocateLockedDiscardableSharedMemory(client_id, size, id, | 316 AllocateLockedDiscardableSharedMemory(process_handle, client_id, size, id, |
376 shared_memory_handle); | 317 shared_memory_handle); |
377 } | 318 } |
378 | 319 |
379 void DiscardableSharedMemoryManager::ClientDeletedDiscardableSharedMemory( | 320 void DiscardableSharedMemoryManager::ClientDeletedDiscardableSharedMemory( |
380 int32_t id, | 321 DiscardableSharedMemoryId id, |
381 int client_id) { | 322 int client_id) { |
382 DeletedDiscardableSharedMemory(id, client_id); | 323 DeletedDiscardableSharedMemory(id, client_id); |
383 } | 324 } |
384 | 325 |
385 void DiscardableSharedMemoryManager::ClientRemoved(int client_id) { | 326 void DiscardableSharedMemoryManager::ClientRemoved(int client_id) { |
386 base::AutoLock lock(lock_); | 327 base::AutoLock lock(lock_); |
387 | 328 |
388 auto it = clients_.find(client_id); | 329 auto it = clients_.find(client_id); |
389 if (it == clients_.end()) | 330 if (it == clients_.end()) |
390 return; | 331 return; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
432 case base::MemoryState::SUSPENDED: | 373 case base::MemoryState::SUSPENDED: |
433 // Note that SUSPENDED never occurs in the main browser process so far. | 374 // Note that SUSPENDED never occurs in the main browser process so far. |
434 // Fall through. | 375 // Fall through. |
435 case base::MemoryState::UNKNOWN: | 376 case base::MemoryState::UNKNOWN: |
436 NOTREACHED(); | 377 NOTREACHED(); |
437 break; | 378 break; |
438 } | 379 } |
439 } | 380 } |
440 | 381 |
441 void DiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory( | 382 void DiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory( |
| 383 base::ProcessHandle process_handle, |
442 int client_id, | 384 int client_id, |
443 size_t size, | 385 size_t size, |
444 int32_t id, | 386 DiscardableSharedMemoryId id, |
445 base::SharedMemoryHandle* shared_memory_handle) { | 387 base::SharedMemoryHandle* shared_memory_handle) { |
446 base::AutoLock lock(lock_); | 388 base::AutoLock lock(lock_); |
447 | 389 |
448 // Make sure |id| is not already in use. | 390 // Make sure |id| is not already in use. |
449 MemorySegmentMap& client_segments = clients_[client_id]; | 391 MemorySegmentMap& client_segments = clients_[client_id]; |
450 if (client_segments.find(id) != client_segments.end()) { | 392 if (client_segments.find(id) != client_segments.end()) { |
451 LOG(ERROR) << "Invalid discardable shared memory ID"; | 393 LOG(ERROR) << "Invalid discardable shared memory ID"; |
452 *shared_memory_handle = base::SharedMemory::NULLHandle(); | 394 *shared_memory_handle = base::SharedMemory::NULLHandle(); |
453 return; | 395 return; |
454 } | 396 } |
(...skipping 12 matching lines...) Expand all Loading... |
467 if (bytes_allocated_ > limit) | 409 if (bytes_allocated_ > limit) |
468 ReduceMemoryUsageUntilWithinLimit(limit); | 410 ReduceMemoryUsageUntilWithinLimit(limit); |
469 | 411 |
470 std::unique_ptr<base::DiscardableSharedMemory> memory( | 412 std::unique_ptr<base::DiscardableSharedMemory> memory( |
471 new base::DiscardableSharedMemory); | 413 new base::DiscardableSharedMemory); |
472 if (!memory->CreateAndMap(size)) { | 414 if (!memory->CreateAndMap(size)) { |
473 *shared_memory_handle = base::SharedMemory::NULLHandle(); | 415 *shared_memory_handle = base::SharedMemory::NULLHandle(); |
474 return; | 416 return; |
475 } | 417 } |
476 | 418 |
| 419 if (!memory->ShareToProcess(process_handle, shared_memory_handle)) { |
| 420 LOG(ERROR) << "Cannot share discardable memory segment"; |
| 421 *shared_memory_handle = base::SharedMemory::NULLHandle(); |
| 422 return; |
| 423 } |
| 424 |
| 425 // Close file descriptor to avoid running out. |
| 426 memory->Close(); |
| 427 |
477 base::CheckedNumeric<size_t> checked_bytes_allocated = bytes_allocated_; | 428 base::CheckedNumeric<size_t> checked_bytes_allocated = bytes_allocated_; |
478 checked_bytes_allocated += memory->mapped_size(); | 429 checked_bytes_allocated += memory->mapped_size(); |
479 if (!checked_bytes_allocated.IsValid()) { | 430 if (!checked_bytes_allocated.IsValid()) { |
480 *shared_memory_handle = base::SharedMemory::NULLHandle(); | 431 *shared_memory_handle = base::SharedMemory::NULLHandle(); |
481 return; | 432 return; |
482 } | 433 } |
483 | 434 |
484 bytes_allocated_ = checked_bytes_allocated.ValueOrDie(); | 435 bytes_allocated_ = checked_bytes_allocated.ValueOrDie(); |
485 BytesAllocatedChanged(bytes_allocated_); | 436 BytesAllocatedChanged(bytes_allocated_); |
486 | 437 |
487 *shared_memory_handle = base::SharedMemory::DuplicateHandle(memory->handle()); | |
488 // Close file descriptor to avoid running out. | |
489 memory->Close(); | |
490 | |
491 scoped_refptr<MemorySegment> segment(new MemorySegment(std::move(memory))); | 438 scoped_refptr<MemorySegment> segment(new MemorySegment(std::move(memory))); |
492 client_segments[id] = segment.get(); | 439 client_segments[id] = segment.get(); |
493 segments_.push_back(segment.get()); | 440 segments_.push_back(segment.get()); |
494 std::push_heap(segments_.begin(), segments_.end(), CompareMemoryUsageTime); | 441 std::push_heap(segments_.begin(), segments_.end(), CompareMemoryUsageTime); |
495 | 442 |
496 if (bytes_allocated_ > memory_limit_) | 443 if (bytes_allocated_ > memory_limit_) |
497 ScheduleEnforceMemoryPolicy(); | 444 ScheduleEnforceMemoryPolicy(); |
498 } | 445 } |
499 | 446 |
500 void DiscardableSharedMemoryManager::DeletedDiscardableSharedMemory( | 447 void DiscardableSharedMemoryManager::DeletedDiscardableSharedMemory( |
501 int32_t id, | 448 DiscardableSharedMemoryId id, |
502 int client_id) { | 449 int client_id) { |
503 base::AutoLock lock(lock_); | 450 base::AutoLock lock(lock_); |
504 | 451 |
505 MemorySegmentMap& client_segments = clients_[client_id]; | 452 MemorySegmentMap& client_segments = clients_[client_id]; |
506 | 453 |
507 MemorySegmentMap::iterator segment_it = client_segments.find(id); | 454 MemorySegmentMap::iterator segment_it = client_segments.find(id); |
508 if (segment_it == client_segments.end()) { | 455 if (segment_it == client_segments.end()) { |
509 LOG(ERROR) << "Invalid discardable shared memory ID"; | 456 LOG(ERROR) << "Invalid discardable shared memory ID"; |
510 return; | 457 return; |
511 } | 458 } |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
634 return; | 581 return; |
635 | 582 |
636 enforce_memory_policy_pending_ = true; | 583 enforce_memory_policy_pending_ = true; |
637 DCHECK(enforce_memory_policy_task_runner_); | 584 DCHECK(enforce_memory_policy_task_runner_); |
638 enforce_memory_policy_task_runner_->PostDelayedTask( | 585 enforce_memory_policy_task_runner_->PostDelayedTask( |
639 FROM_HERE, enforce_memory_policy_callback_, | 586 FROM_HERE, enforce_memory_policy_callback_, |
640 base::TimeDelta::FromMilliseconds(kEnforceMemoryPolicyDelayMs)); | 587 base::TimeDelta::FromMilliseconds(kEnforceMemoryPolicyDelayMs)); |
641 } | 588 } |
642 | 589 |
643 } // namespace discardable_memory | 590 } // namespace discardable_memory |
OLD | NEW |