Index: base/trace_event/memory_dump_manager.cc |
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc |
index d939eea3cef93ec13f76f2cbd59b31f90a7c8231..5b6913856f669b7beda2d90728800a30d2b354b6 100644 |
--- a/base/trace_event/memory_dump_manager.cc |
+++ b/base/trace_event/memory_dump_manager.cc |
@@ -11,6 +11,7 @@ |
#include "base/command_line.h" |
#include "base/compiler_specific.h" |
#include "base/thread_task_runner_handle.h" |
+#include "base/threading/thread.h" |
#include "base/trace_event/memory_dump_provider.h" |
#include "base/trace_event/memory_dump_session_state.h" |
#include "base/trace_event/memory_profiler_allocation_context.h" |
@@ -282,7 +283,8 @@ void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args, |
{ |
AutoLock lock(lock_); |
pmd_async_state.reset(new ProcessMemoryDumpAsyncState( |
- args, dump_providers_.begin(), session_state_, callback)); |
+ args, dump_providers_.begin(), session_state_, callback, |
+ dump_thread_->task_runner())); |
} |
TRACE_EVENT_WITH_FLOW0(kTraceCategory, "MemoryDumpManager::CreateProcessDump", |
@@ -331,10 +333,21 @@ void MemoryDumpManager::ContinueAsyncProcessDump( |
auto mdp_info = pmd_async_state->next_dump_provider; |
mdp = mdp_info->dump_provider; |
dump_provider_name = mdp_info->name; |
+ |
+ // If the dump provider did not specify a thread affinity, dump on |
+ // |dump_thread_|. |
+ SingleThreadTaskRunner* task_runner = mdp_info->task_runner.get(); |
+ if (!task_runner) |
+ task_runner = pmd_async_state->dump_thread_task_runner.get(); |
+ |
+ // |dump_thread_| might have been Stop()-ed at this point (if tracing was |
+ // disabled in the meanwhile). In such case the PostTask() below will fail. |
+ // |task_runner|, however, should always be non-null. |
+ DCHECK(task_runner); |
+ |
if (mdp_info->disabled || mdp_info->unregistered) { |
skip_dump = true; |
- } else if (mdp_info->task_runner && |
- !mdp_info->task_runner->BelongsToCurrentThread()) { |
+ } else if (!task_runner->BelongsToCurrentThread()) { |
// It's time to hop onto another thread. |
// Copy the callback + arguments just for the unlikley case in which |
@@ -343,9 +356,9 @@ void MemoryDumpManager::ContinueAsyncProcessDump( |
// abort. |
MemoryDumpCallback callback = pmd_async_state->callback; |
scoped_refptr<SingleThreadTaskRunner> callback_task_runner = |
- pmd_async_state->task_runner; |
+ pmd_async_state->callback_task_runner; |
- const bool did_post_task = mdp_info->task_runner->PostTask( |
+ const bool did_post_task = task_runner->PostTask( |
FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump, |
Unretained(this), Passed(pmd_async_state.Pass()))); |
if (did_post_task) |
@@ -407,12 +420,12 @@ void MemoryDumpManager::ContinueAsyncProcessDump( |
void MemoryDumpManager::FinalizeDumpAndAddToTrace( |
scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) { |
const uint64_t dump_guid = pmd_async_state->req_args.dump_guid; |
- if (!pmd_async_state->task_runner->BelongsToCurrentThread()) { |
- scoped_refptr<SingleThreadTaskRunner> task_runner = |
- pmd_async_state->task_runner; |
- task_runner->PostTask(FROM_HERE, |
- Bind(&MemoryDumpManager::FinalizeDumpAndAddToTrace, |
- Passed(pmd_async_state.Pass()))); |
+ if (!pmd_async_state->callback_task_runner->BelongsToCurrentThread()) { |
+ scoped_refptr<SingleThreadTaskRunner> callback_task_runner = |
+ pmd_async_state->callback_task_runner; |
+ callback_task_runner->PostTask( |
+ FROM_HERE, Bind(&MemoryDumpManager::FinalizeDumpAndAddToTrace, |
+ Passed(pmd_async_state.Pass()))); |
return; |
} |
@@ -469,6 +482,13 @@ void MemoryDumpManager::OnTraceLogEnabled() { |
// while the |lock_| is taken; |
TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported(); |
+ // Spin-up the thread used to invoke unbound dump providers. |
+ scoped_ptr<Thread> dump_thread(new Thread("MemoryInfra")); |
+ if (!dump_thread->Start()) { |
+ LOG(ERROR) << "Failed to start the memory-infra thread for tracing"; |
+ return; |
+ } |
+ |
AutoLock lock(lock_); |
DCHECK(delegate_); // At this point we must have a delegate. |
@@ -483,6 +503,8 @@ void MemoryDumpManager::OnTraceLogEnabled() { |
stack_frame_deduplicator); |
} |
+ DCHECK(!dump_thread_); |
+ dump_thread_ = dump_thread.Pass(); |
session_state_ = new MemoryDumpSessionState(stack_frame_deduplicator); |
for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it) { |
@@ -532,10 +554,19 @@ void MemoryDumpManager::OnTraceLogEnabled() { |
} |
void MemoryDumpManager::OnTraceLogDisabled() { |
- AutoLock lock(lock_); |
- periodic_dump_timer_.Stop(); |
subtle::NoBarrier_Store(&memory_tracing_enabled_, 0); |
- session_state_ = nullptr; |
+ scoped_ptr<Thread> dump_thread; |
+ { |
+ AutoLock lock(lock_); |
+ dump_thread = dump_thread_.Pass(); |
+ session_state_ = nullptr; |
+ } |
+ |
+ // Thread stops are blocking and must be performed outside of the |lock_| |
+ // or will deadlock (e.g., if ContinueAsyncProcessDump() tries to acquire it). |
+ periodic_dump_timer_.Stop(); |
+ if (dump_thread) |
+ dump_thread->Stop(); |
} |
uint64_t MemoryDumpManager::GetTracingProcessId() const { |
@@ -559,19 +590,22 @@ bool MemoryDumpManager::MemoryDumpProviderInfo::operator<( |
const MemoryDumpProviderInfo& other) const { |
if (task_runner == other.task_runner) |
return dump_provider < other.dump_provider; |
- return task_runner < other.task_runner; |
+ // Ensure that unbound providers (task_runner == nullptr) always run last. |
+ return !(task_runner < other.task_runner); |
} |
MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState( |
MemoryDumpRequestArgs req_args, |
MemoryDumpProviderInfoSet::iterator next_dump_provider, |
const scoped_refptr<MemoryDumpSessionState>& session_state, |
- MemoryDumpCallback callback) |
+ MemoryDumpCallback callback, |
+ const scoped_refptr<SingleThreadTaskRunner>& dump_thread_task_runner) |
: process_memory_dump(session_state), |
req_args(req_args), |
next_dump_provider(next_dump_provider), |
callback(callback), |
- task_runner(MessageLoop::current()->task_runner()) {} |
+ callback_task_runner(MessageLoop::current()->task_runner()), |
+ dump_thread_task_runner(dump_thread_task_runner) {} |
MemoryDumpManager::ProcessMemoryDumpAsyncState::~ProcessMemoryDumpAsyncState() { |
} |