OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "base/trace_event/memory_dump_manager.h" | 5 #include "base/trace_event/memory_dump_manager.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 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
332 } | 332 } |
333 | 333 |
334 void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args, | 334 void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args, |
335 const MemoryDumpCallback& callback) { | 335 const MemoryDumpCallback& callback) { |
336 TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(kTraceCategory, "ProcessMemoryDump", | 336 TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(kTraceCategory, "ProcessMemoryDump", |
337 TRACE_ID_MANGLE(args.dump_guid)); | 337 TRACE_ID_MANGLE(args.dump_guid)); |
338 | 338 |
339 scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state; | 339 scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state; |
340 { | 340 { |
341 AutoLock lock(lock_); | 341 AutoLock lock(lock_); |
342 pmd_async_state.reset( | 342 // |dump_thread_| can be nullptr is tracing was disabled before reaching |
343 new ProcessMemoryDumpAsyncState(args, dump_providers_, session_state_, | 343 // here. ContinueAsyncProcessDump is robust enough to tolerate it and will |
344 callback, dump_thread_->task_runner())); | 344 // NACK the dump. |
| 345 pmd_async_state.reset(new ProcessMemoryDumpAsyncState( |
| 346 args, dump_providers_, session_state_, callback, |
| 347 dump_thread_ ? dump_thread_->task_runner() : nullptr)); |
345 } | 348 } |
346 | 349 |
347 TRACE_EVENT_WITH_FLOW0(kTraceCategory, "MemoryDumpManager::CreateProcessDump", | 350 TRACE_EVENT_WITH_FLOW0(kTraceCategory, "MemoryDumpManager::CreateProcessDump", |
348 TRACE_ID_MANGLE(args.dump_guid), | 351 TRACE_ID_MANGLE(args.dump_guid), |
349 TRACE_EVENT_FLAG_FLOW_OUT); | 352 TRACE_EVENT_FLAG_FLOW_OUT); |
350 | 353 |
351 // Start the thread hop. |dump_providers_| are kept sorted by thread, so | 354 // Start the thread hop. |dump_providers_| are kept sorted by thread, so |
352 // ContinueAsyncProcessDump will hop at most once per thread (w.r.t. thread | 355 // ContinueAsyncProcessDump will hop at most once per thread (w.r.t. thread |
353 // affinity specified by the MemoryDumpProvider(s) in RegisterDumpProvider()). | 356 // affinity specified by the MemoryDumpProvider(s) in RegisterDumpProvider()). |
354 ContinueAsyncProcessDump(pmd_async_state.release()); | 357 ContinueAsyncProcessDump(pmd_async_state.release()); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
397 | 400 |
398 // If the dump provider did not specify a thread affinity, dump on | 401 // If the dump provider did not specify a thread affinity, dump on |
399 // |dump_thread_|. Note that |dump_thread_| might have been Stop()-ed at this | 402 // |dump_thread_|. Note that |dump_thread_| might have been Stop()-ed at this |
400 // point (if tracing was disabled in the meanwhile). In such case the | 403 // point (if tracing was disabled in the meanwhile). In such case the |
401 // PostTask() below will fail, but |task_runner| should always be non-null. | 404 // PostTask() below will fail, but |task_runner| should always be non-null. |
402 SingleThreadTaskRunner* task_runner = mdpinfo->task_runner.get(); | 405 SingleThreadTaskRunner* task_runner = mdpinfo->task_runner.get(); |
403 if (!task_runner) | 406 if (!task_runner) |
404 task_runner = pmd_async_state->dump_thread_task_runner.get(); | 407 task_runner = pmd_async_state->dump_thread_task_runner.get(); |
405 | 408 |
406 bool post_task_failed = false; | 409 bool post_task_failed = false; |
407 if (!task_runner->BelongsToCurrentThread()) { | 410 if (!task_runner) { |
| 411 // If tracing was disabled before reaching CreateProcessDump() |task_runner| |
| 412 // will be null, as the dump_thread_ would have been already torn down. |
| 413 post_task_failed = true; |
| 414 pmd_async_state->dump_successful = false; |
| 415 } else if (!task_runner->BelongsToCurrentThread()) { |
408 // It's time to hop onto another thread. | 416 // It's time to hop onto another thread. |
409 post_task_failed = !task_runner->PostTask( | 417 post_task_failed = !task_runner->PostTask( |
410 FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump, | 418 FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump, |
411 Unretained(this), Unretained(pmd_async_state.get()))); | 419 Unretained(this), Unretained(pmd_async_state.get()))); |
412 if (!post_task_failed) { | 420 if (!post_task_failed) { |
413 // Ownership is tranferred to the next ContinueAsyncProcessDump(). | 421 // Ownership is tranferred to the next ContinueAsyncProcessDump(). |
414 ignore_result(pmd_async_state.release()); | 422 ignore_result(pmd_async_state.release()); |
415 return; | 423 return; |
416 } | 424 } |
417 } | 425 } |
(...skipping 16 matching lines...) Expand all Loading... |
434 " Try --no-sandbox."; | 442 " Try --no-sandbox."; |
435 } else if (post_task_failed && mdpinfo->task_runner) { | 443 } else if (post_task_failed && mdpinfo->task_runner) { |
436 // Don't disable unbound dump providers. The utility thread is normally | 444 // Don't disable unbound dump providers. The utility thread is normally |
437 // shutdown when disabling the trace and getting here in this case is | 445 // shutdown when disabling the trace and getting here in this case is |
438 // expected. | 446 // expected. |
439 mdpinfo->disabled = true; | 447 mdpinfo->disabled = true; |
440 disabled_reason = "The thread it was meant to dump onto is gone."; | 448 disabled_reason = "The thread it was meant to dump onto is gone."; |
441 } | 449 } |
442 } | 450 } |
443 should_dump = !mdpinfo->disabled && !post_task_failed; | 451 should_dump = !mdpinfo->disabled && !post_task_failed; |
444 } | 452 } // AutoLock lock(lock_); |
445 | 453 |
446 if (disabled_reason) { | 454 if (disabled_reason) { |
447 LOG(ERROR) << "Disabling MemoryDumpProvider \"" << mdpinfo->name << "\". " | 455 LOG(ERROR) << "Disabling MemoryDumpProvider \"" << mdpinfo->name << "\". " |
448 << disabled_reason; | 456 << disabled_reason; |
449 } | 457 } |
450 | 458 |
451 if (should_dump) { | 459 if (should_dump) { |
452 // Invoke the dump provider. | 460 // Invoke the dump provider. |
453 TRACE_EVENT_WITH_FLOW1(kTraceCategory, | 461 TRACE_EVENT_WITH_FLOW1(kTraceCategory, |
454 "MemoryDumpManager::ContinueAsyncProcessDump", | 462 "MemoryDumpManager::ContinueAsyncProcessDump", |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
503 MemoryDumpTypeToString(pmd_async_state->req_args.dump_type); | 511 MemoryDumpTypeToString(pmd_async_state->req_args.dump_type); |
504 | 512 |
505 TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID( | 513 TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID( |
506 TRACE_EVENT_PHASE_MEMORY_DUMP, | 514 TRACE_EVENT_PHASE_MEMORY_DUMP, |
507 TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name, | 515 TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name, |
508 dump_guid, pid, kTraceEventNumArgs, kTraceEventArgNames, | 516 dump_guid, pid, kTraceEventNumArgs, kTraceEventArgNames, |
509 kTraceEventArgTypes, nullptr /* arg_values */, &event_value, | 517 kTraceEventArgTypes, nullptr /* arg_values */, &event_value, |
510 TRACE_EVENT_FLAG_HAS_ID); | 518 TRACE_EVENT_FLAG_HAS_ID); |
511 } | 519 } |
512 | 520 |
| 521 bool tracing_still_enabled; |
| 522 TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &tracing_still_enabled); |
| 523 if (!tracing_still_enabled) |
| 524 pmd_async_state->dump_successful = false; |
| 525 |
513 if (!pmd_async_state->callback.is_null()) { | 526 if (!pmd_async_state->callback.is_null()) { |
514 pmd_async_state->callback.Run(dump_guid, true /* success */); | 527 pmd_async_state->callback.Run(dump_guid, pmd_async_state->dump_successful); |
515 pmd_async_state->callback.Reset(); | 528 pmd_async_state->callback.Reset(); |
516 } | 529 } |
517 | 530 |
518 TRACE_EVENT_NESTABLE_ASYNC_END0(kTraceCategory, "ProcessMemoryDump", | 531 TRACE_EVENT_NESTABLE_ASYNC_END0(kTraceCategory, "ProcessMemoryDump", |
519 TRACE_ID_MANGLE(dump_guid)); | 532 TRACE_ID_MANGLE(dump_guid)); |
520 } | 533 } |
521 | 534 |
522 void MemoryDumpManager::OnTraceLogEnabled() { | 535 void MemoryDumpManager::OnTraceLogEnabled() { |
523 bool enabled; | 536 bool enabled; |
524 TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled); | 537 TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
598 } | 611 } |
599 DCHECK_EQ(0u, heavy_dump_period_ms % min_timer_period_ms); | 612 DCHECK_EQ(0u, heavy_dump_period_ms % min_timer_period_ms); |
600 g_heavy_dumps_rate = heavy_dump_period_ms / min_timer_period_ms; | 613 g_heavy_dumps_rate = heavy_dump_period_ms / min_timer_period_ms; |
601 | 614 |
602 periodic_dump_timer_.Start(FROM_HERE, | 615 periodic_dump_timer_.Start(FROM_HERE, |
603 TimeDelta::FromMilliseconds(min_timer_period_ms), | 616 TimeDelta::FromMilliseconds(min_timer_period_ms), |
604 base::Bind(&RequestPeriodicGlobalDump)); | 617 base::Bind(&RequestPeriodicGlobalDump)); |
605 } | 618 } |
606 | 619 |
607 void MemoryDumpManager::OnTraceLogDisabled() { | 620 void MemoryDumpManager::OnTraceLogDisabled() { |
| 621 // There might be a memory dump in progress while this happens. Therefore, |
| 622 // ensure that the MDM state which depends on the tracing enabled / disabled |
| 623 // state is always accessed by the dumping methods holding the |lock_|. |
608 subtle::NoBarrier_Store(&memory_tracing_enabled_, 0); | 624 subtle::NoBarrier_Store(&memory_tracing_enabled_, 0); |
609 scoped_ptr<Thread> dump_thread; | 625 scoped_ptr<Thread> dump_thread; |
610 { | 626 { |
611 AutoLock lock(lock_); | 627 AutoLock lock(lock_); |
612 dump_thread = std::move(dump_thread_); | 628 dump_thread = std::move(dump_thread_); |
613 session_state_ = nullptr; | 629 session_state_ = nullptr; |
614 } | 630 } |
615 | 631 |
616 // Thread stops are blocking and must be performed outside of the |lock_| | 632 // Thread stops are blocking and must be performed outside of the |lock_| |
617 // or will deadlock (e.g., if ContinueAsyncProcessDump() tries to acquire it). | 633 // or will deadlock (e.g., if ContinueAsyncProcessDump() tries to acquire it). |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
652 | 668 |
653 MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState( | 669 MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState( |
654 MemoryDumpRequestArgs req_args, | 670 MemoryDumpRequestArgs req_args, |
655 const MemoryDumpProviderInfo::OrderedSet& dump_providers, | 671 const MemoryDumpProviderInfo::OrderedSet& dump_providers, |
656 const scoped_refptr<MemoryDumpSessionState>& session_state, | 672 const scoped_refptr<MemoryDumpSessionState>& session_state, |
657 MemoryDumpCallback callback, | 673 MemoryDumpCallback callback, |
658 const scoped_refptr<SingleThreadTaskRunner>& dump_thread_task_runner) | 674 const scoped_refptr<SingleThreadTaskRunner>& dump_thread_task_runner) |
659 : req_args(req_args), | 675 : req_args(req_args), |
660 session_state(session_state), | 676 session_state(session_state), |
661 callback(callback), | 677 callback(callback), |
| 678 dump_successful(true), |
662 callback_task_runner(MessageLoop::current()->task_runner()), | 679 callback_task_runner(MessageLoop::current()->task_runner()), |
663 dump_thread_task_runner(dump_thread_task_runner) { | 680 dump_thread_task_runner(dump_thread_task_runner) { |
664 pending_dump_providers.reserve(dump_providers.size()); | 681 pending_dump_providers.reserve(dump_providers.size()); |
665 pending_dump_providers.assign(dump_providers.rbegin(), dump_providers.rend()); | 682 pending_dump_providers.assign(dump_providers.rbegin(), dump_providers.rend()); |
666 } | 683 } |
667 | 684 |
668 MemoryDumpManager::ProcessMemoryDumpAsyncState::~ProcessMemoryDumpAsyncState() { | 685 MemoryDumpManager::ProcessMemoryDumpAsyncState::~ProcessMemoryDumpAsyncState() { |
669 } | 686 } |
670 | 687 |
671 ProcessMemoryDump* MemoryDumpManager::ProcessMemoryDumpAsyncState:: | 688 ProcessMemoryDump* MemoryDumpManager::ProcessMemoryDumpAsyncState:: |
672 GetOrCreateMemoryDumpContainerForProcess(ProcessId pid) { | 689 GetOrCreateMemoryDumpContainerForProcess(ProcessId pid) { |
673 auto iter = process_dumps.find(pid); | 690 auto iter = process_dumps.find(pid); |
674 if (iter == process_dumps.end()) { | 691 if (iter == process_dumps.end()) { |
675 scoped_ptr<ProcessMemoryDump> new_pmd(new ProcessMemoryDump(session_state)); | 692 scoped_ptr<ProcessMemoryDump> new_pmd(new ProcessMemoryDump(session_state)); |
676 iter = process_dumps.insert(std::make_pair(pid, std::move(new_pmd))).first; | 693 iter = process_dumps.insert(std::make_pair(pid, std::move(new_pmd))).first; |
677 } | 694 } |
678 return iter->second.get(); | 695 return iter->second.get(); |
679 } | 696 } |
680 | 697 |
681 } // namespace trace_event | 698 } // namespace trace_event |
682 } // namespace base | 699 } // namespace base |
OLD | NEW |