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

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: 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 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 } 301 }
302 302
303 void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args, 303 void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args,
304 const MemoryDumpCallback& callback) { 304 const MemoryDumpCallback& callback) {
305 TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(kTraceCategory, "ProcessMemoryDump", 305 TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(kTraceCategory, "ProcessMemoryDump",
306 TRACE_ID_MANGLE(args.dump_guid)); 306 TRACE_ID_MANGLE(args.dump_guid));
307 307
308 scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state; 308 scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state;
309 { 309 {
310 AutoLock lock(lock_); 310 AutoLock lock(lock_);
311 pmd_async_state.reset( 311 // |dump_thread_| can be nullptr is tracing was disabled before reaching
312 new ProcessMemoryDumpAsyncState(args, dump_providers_, session_state_, 312 // here. ContinueAsyncProcessDump is robust enough to tolerate it and will
313 callback, dump_thread_->task_runner())); 313 // NACK the dump.
314 pmd_async_state.reset(new ProcessMemoryDumpAsyncState(
315 args, dump_providers_, session_state_, callback,
316 dump_thread_ ? dump_thread_->task_runner() : nullptr));
314 } 317 }
315 318
316 TRACE_EVENT_WITH_FLOW0(kTraceCategory, "MemoryDumpManager::CreateProcessDump", 319 TRACE_EVENT_WITH_FLOW0(kTraceCategory, "MemoryDumpManager::CreateProcessDump",
317 TRACE_ID_MANGLE(args.dump_guid), 320 TRACE_ID_MANGLE(args.dump_guid),
318 TRACE_EVENT_FLAG_FLOW_OUT); 321 TRACE_EVENT_FLAG_FLOW_OUT);
319 322
320 // Start the thread hop. |dump_providers_| are kept sorted by thread, so 323 // Start the thread hop. |dump_providers_| are kept sorted by thread, so
321 // ContinueAsyncProcessDump will hop at most once per thread (w.r.t. thread 324 // ContinueAsyncProcessDump will hop at most once per thread (w.r.t. thread
322 // affinity specified by the MemoryDumpProvider(s) in RegisterDumpProvider()). 325 // affinity specified by the MemoryDumpProvider(s) in RegisterDumpProvider()).
323 ContinueAsyncProcessDump(pmd_async_state.release()); 326 ContinueAsyncProcessDump(pmd_async_state.release());
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
366 369
367 // If the dump provider did not specify a thread affinity, dump on 370 // If the dump provider did not specify a thread affinity, dump on
368 // |dump_thread_|. Note that |dump_thread_| might have been Stop()-ed at this 371 // |dump_thread_|. Note that |dump_thread_| might have been Stop()-ed at this
369 // point (if tracing was disabled in the meanwhile). In such case the 372 // point (if tracing was disabled in the meanwhile). In such case the
370 // PostTask() below will fail, but |task_runner| should always be non-null. 373 // PostTask() below will fail, but |task_runner| should always be non-null.
371 SingleThreadTaskRunner* task_runner = mdpinfo->task_runner.get(); 374 SingleThreadTaskRunner* task_runner = mdpinfo->task_runner.get();
372 if (!task_runner) 375 if (!task_runner)
373 task_runner = pmd_async_state->dump_thread_task_runner.get(); 376 task_runner = pmd_async_state->dump_thread_task_runner.get();
374 377
375 bool post_task_failed = false; 378 bool post_task_failed = false;
376 if (!task_runner->BelongsToCurrentThread()) { 379 if (!task_runner) {
380 // If tracing was disabled before reaching CreateProcessDump() |task_runner|
381 // will be null, as the dump_thread_ would have been already torn down.
382 post_task_failed = true;
383 pmd_async_state->dump_successful = false;
384 } else if (!task_runner->BelongsToCurrentThread()) {
377 // It's time to hop onto another thread. 385 // It's time to hop onto another thread.
378 post_task_failed = !task_runner->PostTask( 386 post_task_failed = !task_runner->PostTask(
379 FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump, 387 FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump,
380 Unretained(this), Unretained(pmd_async_state.get()))); 388 Unretained(this), Unretained(pmd_async_state.get())));
381 if (!post_task_failed) { 389 if (!post_task_failed) {
382 // Ownership is tranferred to the next ContinueAsyncProcessDump(). 390 // Ownership is tranferred to the next ContinueAsyncProcessDump().
383 ignore_result(pmd_async_state.release()); 391 ignore_result(pmd_async_state.release());
384 return; 392 return;
385 } 393 }
386 } 394 }
(...skipping 16 matching lines...) Expand all
403 " Try --no-sandbox."; 411 " Try --no-sandbox.";
404 } else if (post_task_failed && mdpinfo->task_runner) { 412 } else if (post_task_failed && mdpinfo->task_runner) {
405 // Don't disable unbound dump providers. The utility thread is normally 413 // Don't disable unbound dump providers. The utility thread is normally
406 // shutdown when disabling the trace and getting here in this case is 414 // shutdown when disabling the trace and getting here in this case is
407 // expected. 415 // expected.
408 mdpinfo->disabled = true; 416 mdpinfo->disabled = true;
409 disabled_reason = "The thread it was meant to dump onto is gone."; 417 disabled_reason = "The thread it was meant to dump onto is gone.";
410 } 418 }
411 } 419 }
412 should_dump = !mdpinfo->disabled && !post_task_failed; 420 should_dump = !mdpinfo->disabled && !post_task_failed;
413 } 421 } // AutoLock lock(lock_);
414 422
415 if (disabled_reason) { 423 if (disabled_reason) {
416 LOG(ERROR) << "Disabling MemoryDumpProvider \"" << mdpinfo->name << "\". " 424 LOG(ERROR) << "Disabling MemoryDumpProvider \"" << mdpinfo->name << "\". "
417 << disabled_reason; 425 << disabled_reason;
418 } 426 }
419 427
420 if (should_dump) { 428 if (should_dump) {
421 // Invoke the dump provider. 429 // Invoke the dump provider.
422 TRACE_EVENT_WITH_FLOW1(kTraceCategory, 430 TRACE_EVENT_WITH_FLOW1(kTraceCategory,
423 "MemoryDumpManager::ContinueAsyncProcessDump", 431 "MemoryDumpManager::ContinueAsyncProcessDump",
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
473 481
474 TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID( 482 TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID(
475 TRACE_EVENT_PHASE_MEMORY_DUMP, 483 TRACE_EVENT_PHASE_MEMORY_DUMP,
476 TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name, 484 TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name,
477 dump_guid, pid, kTraceEventNumArgs, kTraceEventArgNames, 485 dump_guid, pid, kTraceEventNumArgs, kTraceEventArgNames,
478 kTraceEventArgTypes, nullptr /* arg_values */, &event_value, 486 kTraceEventArgTypes, nullptr /* arg_values */, &event_value,
479 TRACE_EVENT_FLAG_HAS_ID); 487 TRACE_EVENT_FLAG_HAS_ID);
480 } 488 }
481 489
482 if (!pmd_async_state->callback.is_null()) { 490 if (!pmd_async_state->callback.is_null()) {
483 pmd_async_state->callback.Run(dump_guid, true /* success */); 491 pmd_async_state->callback.Run(dump_guid, pmd_async_state->dump_successful);
ssid 2016/01/22 15:31:14 This used to always return true and currently the
Primiano Tucci (use gerrit) 2016/01/25 16:29:39 You are right. Done.
484 pmd_async_state->callback.Reset(); 492 pmd_async_state->callback.Reset();
485 } 493 }
486 494
487 TRACE_EVENT_NESTABLE_ASYNC_END0(kTraceCategory, "ProcessMemoryDump", 495 TRACE_EVENT_NESTABLE_ASYNC_END0(kTraceCategory, "ProcessMemoryDump",
488 TRACE_ID_MANGLE(dump_guid)); 496 TRACE_ID_MANGLE(dump_guid));
489 } 497 }
490 498
491 void MemoryDumpManager::OnTraceLogEnabled() { 499 void MemoryDumpManager::OnTraceLogEnabled() {
492 bool enabled; 500 bool enabled;
493 TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled); 501 TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled);
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
567 } 575 }
568 DCHECK_EQ(0u, heavy_dump_period_ms % min_timer_period_ms); 576 DCHECK_EQ(0u, heavy_dump_period_ms % min_timer_period_ms);
569 g_heavy_dumps_rate = heavy_dump_period_ms / min_timer_period_ms; 577 g_heavy_dumps_rate = heavy_dump_period_ms / min_timer_period_ms;
570 578
571 periodic_dump_timer_.Start(FROM_HERE, 579 periodic_dump_timer_.Start(FROM_HERE,
572 TimeDelta::FromMilliseconds(min_timer_period_ms), 580 TimeDelta::FromMilliseconds(min_timer_period_ms),
573 base::Bind(&RequestPeriodicGlobalDump)); 581 base::Bind(&RequestPeriodicGlobalDump));
574 } 582 }
575 583
576 void MemoryDumpManager::OnTraceLogDisabled() { 584 void MemoryDumpManager::OnTraceLogDisabled() {
585 // There might be a memory dump in progress while this happens. Therefore,
586 // ensure that the MDM state which depends on the tracing enabled / disabled
587 // state is always accessed by the dumping methods holding the |lock_|.
577 subtle::NoBarrier_Store(&memory_tracing_enabled_, 0); 588 subtle::NoBarrier_Store(&memory_tracing_enabled_, 0);
578 scoped_ptr<Thread> dump_thread; 589 scoped_ptr<Thread> dump_thread;
579 { 590 {
580 AutoLock lock(lock_); 591 AutoLock lock(lock_);
581 dump_thread = std::move(dump_thread_); 592 dump_thread = std::move(dump_thread_);
582 session_state_ = nullptr; 593 session_state_ = nullptr;
583 } 594 }
584 595
585 // Thread stops are blocking and must be performed outside of the |lock_| 596 // Thread stops are blocking and must be performed outside of the |lock_|
586 // or will deadlock (e.g., if ContinueAsyncProcessDump() tries to acquire it). 597 // or will deadlock (e.g., if ContinueAsyncProcessDump() tries to acquire it).
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
621 632
622 MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState( 633 MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState(
623 MemoryDumpRequestArgs req_args, 634 MemoryDumpRequestArgs req_args,
624 const MemoryDumpProviderInfo::OrderedSet& dump_providers, 635 const MemoryDumpProviderInfo::OrderedSet& dump_providers,
625 const scoped_refptr<MemoryDumpSessionState>& session_state, 636 const scoped_refptr<MemoryDumpSessionState>& session_state,
626 MemoryDumpCallback callback, 637 MemoryDumpCallback callback,
627 const scoped_refptr<SingleThreadTaskRunner>& dump_thread_task_runner) 638 const scoped_refptr<SingleThreadTaskRunner>& dump_thread_task_runner)
628 : req_args(req_args), 639 : req_args(req_args),
629 session_state(session_state), 640 session_state(session_state),
630 callback(callback), 641 callback(callback),
642 dump_successful(true),
631 callback_task_runner(MessageLoop::current()->task_runner()), 643 callback_task_runner(MessageLoop::current()->task_runner()),
632 dump_thread_task_runner(dump_thread_task_runner) { 644 dump_thread_task_runner(dump_thread_task_runner) {
633 pending_dump_providers.reserve(dump_providers.size()); 645 pending_dump_providers.reserve(dump_providers.size());
634 pending_dump_providers.assign(dump_providers.rbegin(), dump_providers.rend()); 646 pending_dump_providers.assign(dump_providers.rbegin(), dump_providers.rend());
635 } 647 }
636 648
637 MemoryDumpManager::ProcessMemoryDumpAsyncState::~ProcessMemoryDumpAsyncState() { 649 MemoryDumpManager::ProcessMemoryDumpAsyncState::~ProcessMemoryDumpAsyncState() {
638 } 650 }
639 651
640 ProcessMemoryDump* MemoryDumpManager::ProcessMemoryDumpAsyncState:: 652 ProcessMemoryDump* MemoryDumpManager::ProcessMemoryDumpAsyncState::
641 GetOrCreateMemoryDumpContainerForProcess(ProcessId pid) { 653 GetOrCreateMemoryDumpContainerForProcess(ProcessId pid) {
642 auto iter = process_dumps.find(pid); 654 auto iter = process_dumps.find(pid);
643 if (iter == process_dumps.end()) { 655 if (iter == process_dumps.end()) {
644 scoped_ptr<ProcessMemoryDump> new_pmd(new ProcessMemoryDump(session_state)); 656 scoped_ptr<ProcessMemoryDump> new_pmd(new ProcessMemoryDump(session_state));
645 iter = process_dumps.insert(std::make_pair(pid, std::move(new_pmd))).first; 657 iter = process_dumps.insert(std::make_pair(pid, std::move(new_pmd))).first;
646 } 658 }
647 return iter->second.get(); 659 return iter->second.get();
648 } 660 }
649 661
650 } // namespace trace_event 662 } // namespace trace_event
651 } // namespace base 663 } // 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