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 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |