Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(176)

Side by Side Diff: base/trace_event/memory_dump_manager.cc

Issue 1620783002: tracing: fix edge case when dumping while trace being disabled (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « base/trace_event/memory_dump_manager.h ('k') | base/trace_event/memory_dump_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698