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..133ee13efd777e7b7eb01c69283dd963b1d39646 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 the |
petrcermak
2015/10/30 17:43:04
nit: "dump_thread_" is a name so I'd drop the arti
Primiano Tucci (use gerrit)
2015/11/02 10:22:22
Done.
|
+ // |dump_thread_|. |
+ SingleThreadTaskRunner* task_runner = mdp_info->task_runner.get(); |
+ if (!task_runner) |
+ task_runner = pmd_async_state->dump_thread_task_runner.get(); |
+ |
+ // The |dump_thread_| might have been Stop()-ed at this point (if tracing |
petrcermak
2015/10/30 17:43:04
ditto
Primiano Tucci (use gerrit)
2015/11/02 10:22:22
Done.
|
+ // was disabled in the meanwhile). In such case the PostTask() below will |
+ // fail. The task_runner handle, 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; |
} |
@@ -483,6 +496,9 @@ void MemoryDumpManager::OnTraceLogEnabled() { |
stack_frame_deduplicator); |
} |
+ dump_thread_.reset(new Thread("MemoryInfra")); |
+ dump_thread_->Start(); |
Ruud van Asseldonk
2015/10/30 16:52:41
Is |new Thread| or |dump_thread_->Start()| an expe
petrcermak
2015/10/30 17:43:04
It seems like that could create a race with OnTrac
Primiano Tucci (use gerrit)
2015/11/02 10:22:23
Makes sense, moved to a temporary ref_ptr before a
|
+ |
session_state_ = new MemoryDumpSessionState(stack_frame_deduplicator); |
for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it) { |
@@ -532,9 +548,16 @@ void MemoryDumpManager::OnTraceLogEnabled() { |
} |
void MemoryDumpManager::OnTraceLogDisabled() { |
- AutoLock lock(lock_); |
- periodic_dump_timer_.Stop(); |
subtle::NoBarrier_Store(&memory_tracing_enabled_, 0); |
+ |
+ // 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_) |
Ruud van Asseldonk
2015/10/30 16:52:41
So |dump_thread_| is set inside the lock everywher
petrcermak
2015/10/30 17:43:04
I agree that would be better. It's strange (and po
Primiano Tucci (use gerrit)
2015/11/02 10:22:23
So, tecnically is fine as it is accessed only in O
|
+ dump_thread_->Stop(); |
+ |
+ AutoLock lock(lock_); |
+ dump_thread_.reset(); |
session_state_ = nullptr; |
} |
@@ -559,19 +582,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) run always last. |
petrcermak
2015/10/30 17:43:04
supernit: "always run" sounds better than "run alw
Primiano Tucci (use gerrit)
2015/11/02 10:22:23
Done.
|
+ return !(task_runner < other.task_runner); |
Ruud van Asseldonk
2015/10/30 16:52:41
You replaced < with >= here but we already know th
Primiano Tucci (use gerrit)
2015/11/02 10:22:23
The reason why I did that is that operator< is alr
Ruud van Asseldonk
2015/11/02 11:00:37
I see. You could call |.get()| to work around.
|
} |
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() { |
} |