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 | 8 |
9 #include "base/atomic_sequence_num.h" | 9 #include "base/atomic_sequence_num.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 } | 86 } |
87 | 87 |
88 // static | 88 // static |
89 void MemoryDumpManager::SetInstanceForTesting(MemoryDumpManager* instance) { | 89 void MemoryDumpManager::SetInstanceForTesting(MemoryDumpManager* instance) { |
90 if (instance) | 90 if (instance) |
91 instance->skip_core_dumpers_auto_registration_for_testing_ = true; | 91 instance->skip_core_dumpers_auto_registration_for_testing_ = true; |
92 g_instance_for_testing = instance; | 92 g_instance_for_testing = instance; |
93 } | 93 } |
94 | 94 |
95 MemoryDumpManager::MemoryDumpManager() | 95 MemoryDumpManager::MemoryDumpManager() |
96 : did_unregister_dump_provider_(false), | 96 : delegate_(nullptr), |
97 delegate_(nullptr), | |
98 memory_tracing_enabled_(0), | 97 memory_tracing_enabled_(0), |
99 tracing_process_id_(kInvalidTracingProcessId), | 98 tracing_process_id_(kInvalidTracingProcessId), |
100 system_allocator_pool_name_(nullptr), | 99 system_allocator_pool_name_(nullptr), |
101 skip_core_dumpers_auto_registration_for_testing_(false) { | 100 skip_core_dumpers_auto_registration_for_testing_(false) { |
102 g_next_guid.GetNext(); // Make sure that first guid is not zero. | 101 g_next_guid.GetNext(); // Make sure that first guid is not zero. |
103 } | 102 } |
104 | 103 |
105 MemoryDumpManager::~MemoryDumpManager() { | 104 MemoryDumpManager::~MemoryDumpManager() { |
106 base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this); | 105 base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this); |
107 } | 106 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
145 AutoLock lock(lock_); | 144 AutoLock lock(lock_); |
146 DCHECK_EQ(static_cast<MemoryDumpManagerDelegate*>(nullptr), delegate_); | 145 DCHECK_EQ(static_cast<MemoryDumpManagerDelegate*>(nullptr), delegate_); |
147 delegate_ = delegate; | 146 delegate_ = delegate; |
148 } | 147 } |
149 | 148 |
150 void MemoryDumpManager::RegisterDumpProvider( | 149 void MemoryDumpManager::RegisterDumpProvider( |
151 MemoryDumpProvider* mdp, | 150 MemoryDumpProvider* mdp, |
152 const scoped_refptr<SingleThreadTaskRunner>& task_runner) { | 151 const scoped_refptr<SingleThreadTaskRunner>& task_runner) { |
153 MemoryDumpProviderInfo mdp_info(mdp, task_runner); | 152 MemoryDumpProviderInfo mdp_info(mdp, task_runner); |
154 AutoLock lock(lock_); | 153 AutoLock lock(lock_); |
155 dump_providers_.insert(mdp_info); | 154 auto iter_new = dump_providers_.insert(mdp_info); |
| 155 |
| 156 // If there was a previous entry, replace it with the new one. This is to deal |
| 157 // with the case where a dump provider unregisters itself and then re- |
| 158 // registers before a memory dump happens, so its entry was still in the |
| 159 // collection but flagged |unregistered|. |
| 160 if (!iter_new.second) { |
| 161 dump_providers_.erase(iter_new.first); |
| 162 dump_providers_.insert(mdp_info); |
| 163 } |
156 } | 164 } |
157 | 165 |
158 void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider* mdp) { | 166 void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider* mdp) { |
159 RegisterDumpProvider(mdp, nullptr); | 167 RegisterDumpProvider(mdp, nullptr); |
160 } | 168 } |
161 | 169 |
162 void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) { | 170 void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) { |
163 AutoLock lock(lock_); | 171 AutoLock lock(lock_); |
164 | 172 |
165 auto mdp_iter = dump_providers_.begin(); | 173 auto mdp_iter = dump_providers_.begin(); |
(...skipping 10 matching lines...) Expand all Loading... |
176 // the unregistration happens on the same thread (so the MDP cannot unregister | 184 // the unregistration happens on the same thread (so the MDP cannot unregister |
177 // and OnMemoryDump() at the same time). | 185 // and OnMemoryDump() at the same time). |
178 // Otherwise, it is not possible to guarantee that its unregistration is | 186 // Otherwise, it is not possible to guarantee that its unregistration is |
179 // race-free. If you hit this DCHECK, your MDP has a bug. | 187 // race-free. If you hit this DCHECK, your MDP has a bug. |
180 DCHECK_IMPLIES( | 188 DCHECK_IMPLIES( |
181 subtle::NoBarrier_Load(&memory_tracing_enabled_), | 189 subtle::NoBarrier_Load(&memory_tracing_enabled_), |
182 mdp_iter->task_runner && mdp_iter->task_runner->BelongsToCurrentThread()) | 190 mdp_iter->task_runner && mdp_iter->task_runner->BelongsToCurrentThread()) |
183 << "The MemoryDumpProvider attempted to unregister itself in a racy way. " | 191 << "The MemoryDumpProvider attempted to unregister itself in a racy way. " |
184 << "Please file a crbug."; | 192 << "Please file a crbug."; |
185 | 193 |
186 dump_providers_.erase(mdp_iter); | 194 mdp_iter->unregistered = true; |
187 did_unregister_dump_provider_ = true; | |
188 } | 195 } |
189 | 196 |
190 void MemoryDumpManager::RequestGlobalDump(MemoryDumpType dump_type, | 197 void MemoryDumpManager::RequestGlobalDump(MemoryDumpType dump_type, |
191 const MemoryDumpArgs& dump_args, | 198 const MemoryDumpArgs& dump_args, |
192 const MemoryDumpCallback& callback) { | 199 const MemoryDumpCallback& callback) { |
193 // Bail out immediately if tracing is not enabled at all. | 200 // Bail out immediately if tracing is not enabled at all. |
194 if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_))) { | 201 if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_))) { |
195 if (!callback.is_null()) | 202 if (!callback.is_null()) |
196 callback.Run(0u /* guid */, false /* success */); | 203 callback.Run(0u /* guid */, false /* success */); |
197 return; | 204 return; |
(...skipping 23 matching lines...) Expand all Loading... |
221 void MemoryDumpManager::RequestGlobalDump(MemoryDumpType dump_type, | 228 void MemoryDumpManager::RequestGlobalDump(MemoryDumpType dump_type, |
222 const MemoryDumpArgs& dump_args) { | 229 const MemoryDumpArgs& dump_args) { |
223 RequestGlobalDump(dump_type, dump_args, MemoryDumpCallback()); | 230 RequestGlobalDump(dump_type, dump_args, MemoryDumpCallback()); |
224 } | 231 } |
225 | 232 |
226 void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args, | 233 void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args, |
227 const MemoryDumpCallback& callback) { | 234 const MemoryDumpCallback& callback) { |
228 scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state; | 235 scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state; |
229 { | 236 { |
230 AutoLock lock(lock_); | 237 AutoLock lock(lock_); |
231 did_unregister_dump_provider_ = false; | |
232 pmd_async_state.reset(new ProcessMemoryDumpAsyncState( | 238 pmd_async_state.reset(new ProcessMemoryDumpAsyncState( |
233 args, dump_providers_.begin(), session_state_, callback)); | 239 args, dump_providers_.begin(), session_state_, callback)); |
234 } | 240 } |
235 | 241 |
236 // Start the thread hop. |dump_providers_| are kept sorted by thread, so | 242 // Start the thread hop. |dump_providers_| are kept sorted by thread, so |
237 // ContinueAsyncProcessDump will hop at most once per thread (w.r.t. thread | 243 // ContinueAsyncProcessDump will hop at most once per thread (w.r.t. thread |
238 // affinity specified by the MemoryDumpProvider(s) in RegisterDumpProvider()). | 244 // affinity specified by the MemoryDumpProvider(s) in RegisterDumpProvider()). |
239 ContinueAsyncProcessDump(pmd_async_state.Pass()); | 245 ContinueAsyncProcessDump(pmd_async_state.Pass()); |
240 } | 246 } |
241 | 247 |
(...skipping 19 matching lines...) Expand all Loading... |
261 // in the PostTask below don't end up registering their own dump providers | 267 // in the PostTask below don't end up registering their own dump providers |
262 // (for discounting trace memory overhead) while holding the |lock_|. | 268 // (for discounting trace memory overhead) while holding the |lock_|. |
263 TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported(); | 269 TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported(); |
264 | 270 |
265 // DO NOT put any LOG() statement in the locked sections, as in some contexts | 271 // DO NOT put any LOG() statement in the locked sections, as in some contexts |
266 // (GPU process) LOG() ends up performing PostTask/IPCs. | 272 // (GPU process) LOG() ends up performing PostTask/IPCs. |
267 MemoryDumpProvider* mdp; | 273 MemoryDumpProvider* mdp; |
268 bool skip_dump = false; | 274 bool skip_dump = false; |
269 { | 275 { |
270 AutoLock lock(lock_); | 276 AutoLock lock(lock_); |
271 // In the unlikely event that a dump provider was unregistered while | |
272 // dumping, abort the dump, as that would make |next_dump_provider| invalid. | |
273 // Registration, on the other hand, is safe as per std::set<> contract. | |
274 if (did_unregister_dump_provider_) { | |
275 return AbortDumpLocked(pmd_async_state->callback, | |
276 pmd_async_state->task_runner, | |
277 pmd_async_state->req_args.dump_guid); | |
278 } | |
279 | 277 |
280 auto* mdp_info = &*pmd_async_state->next_dump_provider; | 278 auto mdp_info = pmd_async_state->next_dump_provider; |
281 mdp = mdp_info->dump_provider; | 279 mdp = mdp_info->dump_provider; |
282 if (mdp_info->disabled) { | 280 if (mdp_info->disabled || mdp_info->unregistered) { |
283 skip_dump = true; | 281 skip_dump = true; |
284 } else if (mdp_info->task_runner && | 282 } else if (mdp_info->task_runner && |
285 !mdp_info->task_runner->BelongsToCurrentThread()) { | 283 !mdp_info->task_runner->BelongsToCurrentThread()) { |
286 // It's time to hop onto another thread. | 284 // It's time to hop onto another thread. |
287 | 285 |
288 // Copy the callback + arguments just for the unlikley case in which | 286 // Copy the callback + arguments just for the unlikley case in which |
289 // PostTask fails. In such case the Bind helper will destroy the | 287 // PostTask fails. In such case the Bind helper will destroy the |
290 // pmd_async_state and we must keep a copy of the fields to notify the | 288 // pmd_async_state and we must keep a copy of the fields to notify the |
291 // abort. | 289 // abort. |
292 MemoryDumpCallback callback = pmd_async_state->callback; | 290 MemoryDumpCallback callback = pmd_async_state->callback; |
(...skipping 18 matching lines...) Expand all Loading... |
311 bool finalize = false; | 309 bool finalize = false; |
312 bool dump_successful = false; | 310 bool dump_successful = false; |
313 | 311 |
314 if (!skip_dump) { | 312 if (!skip_dump) { |
315 dump_successful = mdp->OnMemoryDump(pmd_async_state->req_args.dump_args, | 313 dump_successful = mdp->OnMemoryDump(pmd_async_state->req_args.dump_args, |
316 &pmd_async_state->process_memory_dump); | 314 &pmd_async_state->process_memory_dump); |
317 } | 315 } |
318 | 316 |
319 { | 317 { |
320 AutoLock lock(lock_); | 318 AutoLock lock(lock_); |
321 if (did_unregister_dump_provider_) { | 319 auto mdp_info = pmd_async_state->next_dump_provider; |
322 return AbortDumpLocked(pmd_async_state->callback, | |
323 pmd_async_state->task_runner, | |
324 pmd_async_state->req_args.dump_guid); | |
325 } | |
326 auto* mdp_info = &*pmd_async_state->next_dump_provider; | |
327 if (dump_successful) { | 320 if (dump_successful) { |
328 mdp_info->consecutive_failures = 0; | 321 mdp_info->consecutive_failures = 0; |
329 } else if (!skip_dump) { | 322 } else if (!skip_dump) { |
330 ++mdp_info->consecutive_failures; | 323 ++mdp_info->consecutive_failures; |
331 if (mdp_info->consecutive_failures >= kMaxConsecutiveFailuresCount) { | 324 if (mdp_info->consecutive_failures >= kMaxConsecutiveFailuresCount) { |
332 mdp_info->disabled = true; | 325 mdp_info->disabled = true; |
333 } | 326 } |
334 } | 327 } |
335 ++pmd_async_state->next_dump_provider; | 328 ++pmd_async_state->next_dump_provider; |
336 finalize = pmd_async_state->next_dump_provider == dump_providers_.end(); | 329 finalize = pmd_async_state->next_dump_provider == dump_providers_.end(); |
| 330 |
| 331 if (mdp_info->unregistered) |
| 332 dump_providers_.erase(mdp_info); |
337 } | 333 } |
338 | 334 |
339 if (!skip_dump && !dump_successful) { | 335 if (!skip_dump && !dump_successful) { |
340 LOG(ERROR) << "A memory dumper failed, possibly due to sandboxing " | 336 LOG(ERROR) << "A memory dumper failed, possibly due to sandboxing " |
341 "(crbug.com/461788). Disabling dumper for current process. " | 337 "(crbug.com/461788). Disabling dumper for current process. " |
342 "Try restarting chrome with the --no-sandbox switch."; | 338 "Try restarting chrome with the --no-sandbox switch."; |
343 } | 339 } |
344 | 340 |
345 if (finalize) | 341 if (finalize) |
346 return FinalizeDumpAndAddToTrace(pmd_async_state.Pass()); | 342 return FinalizeDumpAndAddToTrace(pmd_async_state.Pass()); |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
447 uint64 MemoryDumpManager::GetTracingProcessId() const { | 443 uint64 MemoryDumpManager::GetTracingProcessId() const { |
448 return delegate_->GetTracingProcessId(); | 444 return delegate_->GetTracingProcessId(); |
449 } | 445 } |
450 | 446 |
451 MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo( | 447 MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo( |
452 MemoryDumpProvider* dump_provider, | 448 MemoryDumpProvider* dump_provider, |
453 const scoped_refptr<SingleThreadTaskRunner>& task_runner) | 449 const scoped_refptr<SingleThreadTaskRunner>& task_runner) |
454 : dump_provider(dump_provider), | 450 : dump_provider(dump_provider), |
455 task_runner(task_runner), | 451 task_runner(task_runner), |
456 consecutive_failures(0), | 452 consecutive_failures(0), |
457 disabled(false) { | 453 disabled(false), |
458 } | 454 unregistered(false) {} |
459 | 455 |
460 MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() { | 456 MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() { |
461 } | 457 } |
462 | 458 |
463 bool MemoryDumpManager::MemoryDumpProviderInfo::operator<( | 459 bool MemoryDumpManager::MemoryDumpProviderInfo::operator<( |
464 const MemoryDumpProviderInfo& other) const { | 460 const MemoryDumpProviderInfo& other) const { |
465 if (task_runner == other.task_runner) | 461 if (task_runner == other.task_runner) |
466 return dump_provider < other.dump_provider; | 462 return dump_provider < other.dump_provider; |
467 return task_runner < other.task_runner; | 463 return task_runner < other.task_runner; |
468 } | 464 } |
469 | 465 |
470 MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState( | 466 MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState( |
471 MemoryDumpRequestArgs req_args, | 467 MemoryDumpRequestArgs req_args, |
472 MemoryDumpProviderInfoSet::iterator next_dump_provider, | 468 MemoryDumpProviderInfoSet::iterator next_dump_provider, |
473 const scoped_refptr<MemoryDumpSessionState>& session_state, | 469 const scoped_refptr<MemoryDumpSessionState>& session_state, |
474 MemoryDumpCallback callback) | 470 MemoryDumpCallback callback) |
475 : process_memory_dump(session_state), | 471 : process_memory_dump(session_state), |
476 req_args(req_args), | 472 req_args(req_args), |
477 next_dump_provider(next_dump_provider), | 473 next_dump_provider(next_dump_provider), |
478 callback(callback), | 474 callback(callback), |
479 task_runner(MessageLoop::current()->task_runner()) { | 475 task_runner(MessageLoop::current()->task_runner()) { |
480 } | 476 } |
481 | 477 |
482 MemoryDumpManager::ProcessMemoryDumpAsyncState::~ProcessMemoryDumpAsyncState() { | 478 MemoryDumpManager::ProcessMemoryDumpAsyncState::~ProcessMemoryDumpAsyncState() { |
483 } | 479 } |
484 | 480 |
485 } // namespace trace_event | 481 } // namespace trace_event |
486 } // namespace base | 482 } // namespace base |
OLD | NEW |