Chromium Code Reviews| 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 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 210 } | 210 } |
| 211 | 211 |
| 212 void MemoryDumpManager::RegisterDumpProvider( | 212 void MemoryDumpManager::RegisterDumpProvider( |
| 213 MemoryDumpProvider* mdp, | 213 MemoryDumpProvider* mdp, |
| 214 const char* name, | 214 const char* name, |
| 215 const scoped_refptr<SingleThreadTaskRunner>& task_runner) { | 215 const scoped_refptr<SingleThreadTaskRunner>& task_runner) { |
| 216 RegisterDumpProvider(mdp, name, task_runner, MemoryDumpProvider::Options()); | 216 RegisterDumpProvider(mdp, name, task_runner, MemoryDumpProvider::Options()); |
| 217 } | 217 } |
| 218 | 218 |
| 219 void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) { | 219 void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) { |
| 220 UnregisterDumpProviderInternal(mdp, false /* delete_async */); | |
| 221 } | |
| 222 | |
| 223 void MemoryDumpManager::UnregisterAndDeleteDumpProviderAsync( | |
| 224 scoped_ptr<MemoryDumpProvider> mdp) { | |
| 225 UnregisterDumpProviderInternal(mdp.release(), true /* delete_async */); | |
| 226 } | |
| 227 | |
| 228 void MemoryDumpManager::UnregisterDumpProviderInternal( | |
| 229 MemoryDumpProvider* mdp, | |
| 230 bool take_mdp_ownership_and_delete_async) { | |
| 231 scoped_ptr<MemoryDumpProvider> owned_mdp; | |
| 232 if (take_mdp_ownership_and_delete_async) | |
| 233 owned_mdp.reset(mdp); // Auto delete in corner early out cases. | |
| 234 | |
| 220 AutoLock lock(lock_); | 235 AutoLock lock(lock_); |
| 221 | 236 |
| 222 auto mdp_iter = dump_providers_.begin(); | 237 auto mdp_iter = dump_providers_.begin(); |
| 223 for (; mdp_iter != dump_providers_.end(); ++mdp_iter) { | 238 for (; mdp_iter != dump_providers_.end(); ++mdp_iter) { |
| 224 if ((*mdp_iter)->dump_provider == mdp) | 239 if ((*mdp_iter)->dump_provider == mdp) |
| 225 break; | 240 break; |
| 226 } | 241 } |
| 227 | 242 |
| 228 if (mdp_iter == dump_providers_.end()) | 243 if (mdp_iter == dump_providers_.end()) |
| 229 return; | 244 return; // Not registered / already unregistered. |
| 230 | 245 |
| 231 // Unregistration of a MemoryDumpProvider while tracing is ongoing is safe | 246 // If you hit this DCHECK, your dump provider has a bug. |
| 232 // only if the MDP has specified a thread affinity (via task_runner()) AND | 247 // Unregistration of a MemoryDumpProvider is safe only if: |
| 233 // the unregistration happens on the same thread (so the MDP cannot unregister | 248 // - The MDP has specified a thread affinity (via task_runner()) AND |
| 234 // and OnMemoryDump() at the same time). | 249 // the unregistration happens on the same thread (so the MDP cannot |
| 235 // Otherwise, it is not possible to guarantee that its unregistration is | 250 // unregister and be in the middle of a OnMemoryDump() at the same time. |
| 236 // race-free. If you hit this DCHECK, your MDP has a bug. | 251 // - The MDP has NOT specified a thread affinity and its ownership is |
| 237 DCHECK(!subtle::NoBarrier_Load(&memory_tracing_enabled_) || | 252 // transferred via UnregisterAndDeleteDumpProviderAsync(). |
| 238 ((*mdp_iter)->task_runner && | 253 // In all the other cases, it is not possible to guarantee that the |
| 239 (*mdp_iter)->task_runner->BelongsToCurrentThread())) | 254 // unregistration will not race with OnMemoryDump() calls. |
| 240 << "MemoryDumpProvider \"" << (*mdp_iter)->name << "\" attempted to " | 255 if (!take_mdp_ownership_and_delete_async && |
| 241 << "unregister itself in a racy way. Please file a crbug."; | 256 subtle::NoBarrier_Load(&memory_tracing_enabled_)) { |
|
Primiano Tucci (use gerrit)
2015/12/22 15:04:46
ah this logic is wrong.
The else below should be:
Ruud van Asseldonk
2015/12/29 11:32:46
Indeed, disabling tracing should not cause the dum
| |
| 257 DCHECK((*mdp_iter)->task_runner && | |
| 258 (*mdp_iter)->task_runner->BelongsToCurrentThread()) | |
| 259 << "MemoryDumpProvider \"" << (*mdp_iter)->name << "\" attempted to " | |
| 260 << "unregister itself in a racy way. Please file a crbug."; | |
| 261 } else { | |
| 262 // The MDP will be deleted whenever the MDPInfo struct will, that is either: | |
| 263 // - At the end of this function, if no dump is in progress. | |
| 264 // - In the prologue of the ContinueAsyncProcessDump(). | |
| 265 std::swap((*mdp_iter)->owned_dump_provider, owned_mdp); | |
| 266 } | |
| 242 | 267 |
| 243 // The MDPInfo instance can still be referenced by the | 268 // The MDPInfo instance can still be referenced by the |
| 244 // |ProcessMemoryDumpAsyncState.pending_dump_providers|. For this reason | 269 // |ProcessMemoryDumpAsyncState.pending_dump_providers|. For this reason |
| 245 // the MDPInfo is flagged as disabled. It will cause ContinueAsyncProcessDump | 270 // the MDPInfo is flagged as disabled. It will cause ContinueAsyncProcessDump |
| 246 // to just skip it, without actually invoking the |mdp|, which might be | 271 // to just skip it, without actually invoking the |mdp|, which might be |
| 247 // destroyed by the caller soon after this method returns. | 272 // destroyed by the caller soon after this method returns. |
| 248 (*mdp_iter)->disabled = true; | 273 (*mdp_iter)->disabled = true; |
| 249 dump_providers_.erase(mdp_iter); | 274 dump_providers_.erase(mdp_iter); |
| 250 } | 275 } |
| 251 | 276 |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 358 pmd_async_state->pending_dump_providers.back().get(); | 383 pmd_async_state->pending_dump_providers.back().get(); |
| 359 | 384 |
| 360 // If the dump provider did not specify a thread affinity, dump on | 385 // If the dump provider did not specify a thread affinity, dump on |
| 361 // |dump_thread_|. Note that |dump_thread_| might have been Stop()-ed at this | 386 // |dump_thread_|. Note that |dump_thread_| might have been Stop()-ed at this |
| 362 // point (if tracing was disabled in the meanwhile). In such case the | 387 // point (if tracing was disabled in the meanwhile). In such case the |
| 363 // PostTask() below will fail, but |task_runner| should always be non-null. | 388 // PostTask() below will fail, but |task_runner| should always be non-null. |
| 364 SingleThreadTaskRunner* task_runner = mdpinfo->task_runner.get(); | 389 SingleThreadTaskRunner* task_runner = mdpinfo->task_runner.get(); |
| 365 if (!task_runner) | 390 if (!task_runner) |
| 366 task_runner = pmd_async_state->dump_thread_task_runner.get(); | 391 task_runner = pmd_async_state->dump_thread_task_runner.get(); |
| 367 | 392 |
| 393 bool post_task_failed = false; | |
| 368 if (!task_runner->BelongsToCurrentThread()) { | 394 if (!task_runner->BelongsToCurrentThread()) { |
| 369 // It's time to hop onto another thread. | 395 // It's time to hop onto another thread. |
| 370 const bool did_post_task = task_runner->PostTask( | 396 post_task_failed = !task_runner->PostTask( |
| 371 FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump, | 397 FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump, |
| 372 Unretained(this), Unretained(pmd_async_state.get()))); | 398 Unretained(this), Unretained(pmd_async_state.get()))); |
| 373 if (did_post_task) { | 399 if (!post_task_failed) { |
| 374 // Ownership is tranferred to the next ContinueAsyncProcessDump(). | 400 // Ownership is tranferred to the next ContinueAsyncProcessDump(). |
| 375 ignore_result(pmd_async_state.release()); | 401 ignore_result(pmd_async_state.release()); |
| 376 return; | 402 return; |
| 377 } | 403 } |
| 378 // The thread is gone. Skip the dump provider and keep going. | |
| 379 mdpinfo->disabled = true; | |
| 380 } | 404 } |
| 381 | 405 |
| 382 // At this point wither we are on the right thread (|mdpinfo.task_runner|) | 406 // At this point either: |
| 383 // to access mdp fields, or the right thread is gone (and |disabled| == true). | 407 // - The MDP has a task runner affinity and we are on the right thread. |
| 408 // - The MDP has a task runner affinity but the underlying thread is gone, | |
| 409 // hence the above |post_task_failed| == true. | |
| 410 // - The MDP does NOT have a task runner affinity. A locked access is required | |
| 411 // to R/W |disabled| (for the UnregisterAndDeleteDumpProviderAsync() case). | |
| 412 bool skip_dump; | |
| 413 { | |
| 414 AutoLock lock(lock_); | |
| 415 if (mdpinfo->consecutive_failures >= kMaxConsecutiveFailuresCount) { | |
| 416 mdpinfo->disabled = true; | |
| 417 skip_dump = true; | |
| 418 LOG(ERROR) << "MemoryDumpProvider \"" << mdpinfo->name << "\" failed, " | |
|
ssid
2015/12/22 15:50:09
Isn't logging inside lock slow?
Primiano Tucci (use gerrit)
2016/01/04 14:44:38
Done.
| |
| 419 << "possibly due to sandboxing (crbug.com/461788)." | |
|
ssid
2015/12/22 15:50:09
Do you think I should remove this line in my CL, o
Primiano Tucci (use gerrit)
2016/01/04 14:44:38
Done here. and solved the lock issue
| |
| 420 << "Disabling dumper for current process. Try --no-sandbox."; | |
| 421 } else if (post_task_failed) { | |
| 422 // The thread is gone. Disable MDP forever. | |
| 423 mdpinfo->disabled = true; | |
| 424 skip_dump = true; | |
| 425 } else { | |
| 426 // The MDP might have been unregistered while we were hopping threads. | |
|
ssid
2015/12/22 15:50:09
I think this comment is not needed. Moreover the m
Primiano Tucci (use gerrit)
2016/01/04 14:44:38
Right. It's already described in the comment block
| |
| 427 skip_dump = mdpinfo->disabled; | |
| 428 } | |
| 429 } | |
| 384 | 430 |
| 385 if (!mdpinfo->disabled) { | 431 if (!skip_dump) { |
|
ssid
2015/12/22 15:50:09
I wonder why shouldn't this be should_dump or simi
Primiano Tucci (use gerrit)
2016/01/04 14:44:38
Right, with the current logic should_dump makes mo
| |
| 386 // Invoke the dump provider. | 432 // Invoke the dump provider. |
| 387 TRACE_EVENT_WITH_FLOW1(kTraceCategory, | 433 TRACE_EVENT_WITH_FLOW1(kTraceCategory, |
| 388 "MemoryDumpManager::ContinueAsyncProcessDump", | 434 "MemoryDumpManager::ContinueAsyncProcessDump", |
| 389 TRACE_ID_MANGLE(pmd_async_state->req_args.dump_guid), | 435 TRACE_ID_MANGLE(pmd_async_state->req_args.dump_guid), |
| 390 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, | 436 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, |
| 391 "dump_provider.name", mdpinfo->name); | 437 "dump_provider.name", mdpinfo->name); |
| 392 | 438 |
| 393 // Pid of the target process being dumped. Often kNullProcessId (= current | 439 // Pid of the target process being dumped. Often kNullProcessId (= current |
| 394 // process), non-zero when the coordinator process creates dumps on behalf | 440 // process), non-zero when the coordinator process creates dumps on behalf |
| 395 // of child processes (see crbug.com/461788). | 441 // of child processes (see crbug.com/461788). |
| 396 ProcessId target_pid = mdpinfo->options.target_pid; | 442 ProcessId target_pid = mdpinfo->options.target_pid; |
| 397 ProcessMemoryDump* pmd = | 443 ProcessMemoryDump* pmd = |
| 398 pmd_async_state->GetOrCreateMemoryDumpContainerForProcess(target_pid); | 444 pmd_async_state->GetOrCreateMemoryDumpContainerForProcess(target_pid); |
| 399 MemoryDumpArgs args = {pmd_async_state->req_args.level_of_detail}; | 445 MemoryDumpArgs args = {pmd_async_state->req_args.level_of_detail}; |
| 400 bool dump_successful = mdpinfo->dump_provider->OnMemoryDump(args, pmd); | 446 bool dump_successful = mdpinfo->dump_provider->OnMemoryDump(args, pmd); |
| 401 | 447 mdpinfo->consecutive_failures = |
| 402 if (dump_successful) { | 448 dump_successful ? 0 : mdpinfo->consecutive_failures + 1; |
| 403 mdpinfo->consecutive_failures = 0; | |
| 404 } else { | |
| 405 ++mdpinfo->consecutive_failures; | |
| 406 if (mdpinfo->consecutive_failures >= kMaxConsecutiveFailuresCount) { | |
| 407 mdpinfo->disabled = true; | |
| 408 LOG(ERROR) << "MemoryDumpProvider \"" << mdpinfo->name << "\" failed, " | |
| 409 << "possibly due to sandboxing (crbug.com/461788)." | |
| 410 << "Disabling dumper for current process. Try --no-sandbox."; | |
| 411 } | |
| 412 } | |
| 413 } // if (!mdpinfo->disabled) | 449 } // if (!mdpinfo->disabled) |
| 414 | 450 |
| 415 pmd_async_state->pending_dump_providers.pop_back(); | 451 pmd_async_state->pending_dump_providers.pop_back(); |
| 416 ContinueAsyncProcessDump(pmd_async_state.release()); | 452 ContinueAsyncProcessDump(pmd_async_state.release()); |
| 417 } | 453 } |
| 418 | 454 |
| 419 // static | 455 // static |
| 420 void MemoryDumpManager::FinalizeDumpAndAddToTrace( | 456 void MemoryDumpManager::FinalizeDumpAndAddToTrace( |
| 421 scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) { | 457 scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) { |
| 422 DCHECK(pmd_async_state->pending_dump_providers.empty()); | 458 DCHECK(pmd_async_state->pending_dump_providers.empty()); |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 617 auto iter = process_dumps.find(pid); | 653 auto iter = process_dumps.find(pid); |
| 618 if (iter == process_dumps.end()) { | 654 if (iter == process_dumps.end()) { |
| 619 scoped_ptr<ProcessMemoryDump> new_pmd(new ProcessMemoryDump(session_state)); | 655 scoped_ptr<ProcessMemoryDump> new_pmd(new ProcessMemoryDump(session_state)); |
| 620 iter = process_dumps.insert(std::make_pair(pid, std::move(new_pmd))).first; | 656 iter = process_dumps.insert(std::make_pair(pid, std::move(new_pmd))).first; |
| 621 } | 657 } |
| 622 return iter->second.get(); | 658 return iter->second.get(); |
| 623 } | 659 } |
| 624 | 660 |
| 625 } // namespace trace_event | 661 } // namespace trace_event |
| 626 } // namespace base | 662 } // namespace base |
| OLD | NEW |