OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/tracked_objects.h" | 5 #include "base/tracked_objects.h" |
6 | 6 |
7 #include <math.h> | 7 #include <math.h> |
8 | 8 |
9 #include "base/format_macros.h" | 9 #include "base/format_macros.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 Births::Births(const Location& location) | 78 Births::Births(const Location& location) |
79 : BirthOnThread(location), | 79 : BirthOnThread(location), |
80 birth_count_(1) { } | 80 birth_count_(1) { } |
81 | 81 |
82 //------------------------------------------------------------------------------ | 82 //------------------------------------------------------------------------------ |
83 // ThreadData maintains the central data for all births and death. | 83 // ThreadData maintains the central data for all births and death. |
84 | 84 |
85 // static | 85 // static |
86 ThreadData* ThreadData::first_ = NULL; | 86 ThreadData* ThreadData::first_ = NULL; |
87 // static | 87 // static |
88 Lock ThreadData::list_lock_; | 88 base::Lock ThreadData::list_lock_; |
89 | 89 |
90 // static | 90 // static |
91 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; | 91 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; |
92 | 92 |
93 ThreadData::ThreadData() : next_(NULL) { | 93 ThreadData::ThreadData() : next_(NULL) { |
94 // This shouldn't use the MessageLoop::current() LazyInstance since this might | 94 // This shouldn't use the MessageLoop::current() LazyInstance since this might |
95 // be used on a non-joinable thread. | 95 // be used on a non-joinable thread. |
96 // http://crbug.com/62728 | 96 // http://crbug.com/62728 |
97 base::ThreadRestrictions::ScopedAllowSingleton scoped_allow_singleton; | 97 base::ThreadRestrictions::ScopedAllowSingleton scoped_allow_singleton; |
98 message_loop_ = MessageLoop::current(); | 98 message_loop_ = MessageLoop::current(); |
99 } | 99 } |
100 | 100 |
101 ThreadData::~ThreadData() {} | 101 ThreadData::~ThreadData() {} |
102 | 102 |
103 // static | 103 // static |
104 ThreadData* ThreadData::current() { | 104 ThreadData* ThreadData::current() { |
105 if (!tls_index_.initialized()) | 105 if (!tls_index_.initialized()) |
106 return NULL; | 106 return NULL; |
107 | 107 |
108 ThreadData* registry = static_cast<ThreadData*>(tls_index_.Get()); | 108 ThreadData* registry = static_cast<ThreadData*>(tls_index_.Get()); |
109 if (!registry) { | 109 if (!registry) { |
110 // We have to create a new registry for ThreadData. | 110 // We have to create a new registry for ThreadData. |
111 bool too_late_to_create = false; | 111 bool too_late_to_create = false; |
112 { | 112 { |
113 registry = new ThreadData; | 113 registry = new ThreadData; |
114 AutoLock lock(list_lock_); | 114 base::AutoLock lock(list_lock_); |
115 // Use lock to insure we have most recent status. | 115 // Use lock to insure we have most recent status. |
116 if (!IsActive()) { | 116 if (!IsActive()) { |
117 too_late_to_create = true; | 117 too_late_to_create = true; |
118 } else { | 118 } else { |
119 // Use lock to insert into list. | 119 // Use lock to insert into list. |
120 registry->next_ = first_; | 120 registry->next_ = first_; |
121 first_ = registry; | 121 first_ = registry; |
122 } | 122 } |
123 } // Release lock. | 123 } // Release lock. |
124 if (too_late_to_create) { | 124 if (too_late_to_create) { |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
278 | 278 |
279 BirthMap::iterator it = birth_map_.find(location); | 279 BirthMap::iterator it = birth_map_.find(location); |
280 if (it != birth_map_.end()) { | 280 if (it != birth_map_.end()) { |
281 it->second->RecordBirth(); | 281 it->second->RecordBirth(); |
282 return it->second; | 282 return it->second; |
283 } | 283 } |
284 | 284 |
285 Births* tracker = new Births(location); | 285 Births* tracker = new Births(location); |
286 // Lock since the map may get relocated now, and other threads sometimes | 286 // Lock since the map may get relocated now, and other threads sometimes |
287 // snapshot it (but they lock before copying it). | 287 // snapshot it (but they lock before copying it). |
288 AutoLock lock(lock_); | 288 base::AutoLock lock(lock_); |
289 birth_map_[location] = tracker; | 289 birth_map_[location] = tracker; |
290 return tracker; | 290 return tracker; |
291 } | 291 } |
292 | 292 |
293 void ThreadData::TallyADeath(const Births& lifetimes, | 293 void ThreadData::TallyADeath(const Births& lifetimes, |
294 const TimeDelta& duration) { | 294 const TimeDelta& duration) { |
295 { | 295 { |
296 // http://crbug.com/62728 | 296 // http://crbug.com/62728 |
297 base::ThreadRestrictions::ScopedAllowSingleton scoped_allow_singleton; | 297 base::ThreadRestrictions::ScopedAllowSingleton scoped_allow_singleton; |
298 if (!message_loop_) // In case message loop wasn't yet around... | 298 if (!message_loop_) // In case message loop wasn't yet around... |
299 message_loop_ = MessageLoop::current(); // Find it now. | 299 message_loop_ = MessageLoop::current(); // Find it now. |
300 } | 300 } |
301 | 301 |
302 DeathMap::iterator it = death_map_.find(&lifetimes); | 302 DeathMap::iterator it = death_map_.find(&lifetimes); |
303 if (it != death_map_.end()) { | 303 if (it != death_map_.end()) { |
304 it->second.RecordDeath(duration); | 304 it->second.RecordDeath(duration); |
305 return; | 305 return; |
306 } | 306 } |
307 | 307 |
308 AutoLock lock(lock_); // Lock since the map may get relocated now. | 308 base::AutoLock lock(lock_); // Lock since the map may get relocated now. |
309 death_map_[&lifetimes].RecordDeath(duration); | 309 death_map_[&lifetimes].RecordDeath(duration); |
310 } | 310 } |
311 | 311 |
312 // static | 312 // static |
313 ThreadData* ThreadData::first() { | 313 ThreadData* ThreadData::first() { |
314 AutoLock lock(list_lock_); | 314 base::AutoLock lock(list_lock_); |
315 return first_; | 315 return first_; |
316 } | 316 } |
317 | 317 |
318 const std::string ThreadData::ThreadName() const { | 318 const std::string ThreadData::ThreadName() const { |
319 if (message_loop_) | 319 if (message_loop_) |
320 return message_loop_->thread_name(); | 320 return message_loop_->thread_name(); |
321 return "ThreadWithoutMessageLoop"; | 321 return "ThreadWithoutMessageLoop"; |
322 } | 322 } |
323 | 323 |
324 // This may be called from another thread. | 324 // This may be called from another thread. |
325 void ThreadData::SnapshotBirthMap(BirthMap *output) const { | 325 void ThreadData::SnapshotBirthMap(BirthMap *output) const { |
326 AutoLock lock(lock_); | 326 base::AutoLock lock(lock_); |
327 for (BirthMap::const_iterator it = birth_map_.begin(); | 327 for (BirthMap::const_iterator it = birth_map_.begin(); |
328 it != birth_map_.end(); ++it) | 328 it != birth_map_.end(); ++it) |
329 (*output)[it->first] = it->second; | 329 (*output)[it->first] = it->second; |
330 } | 330 } |
331 | 331 |
332 // This may be called from another thread. | 332 // This may be called from another thread. |
333 void ThreadData::SnapshotDeathMap(DeathMap *output) const { | 333 void ThreadData::SnapshotDeathMap(DeathMap *output) const { |
334 AutoLock lock(lock_); | 334 base::AutoLock lock(lock_); |
335 for (DeathMap::const_iterator it = death_map_.begin(); | 335 for (DeathMap::const_iterator it = death_map_.begin(); |
336 it != death_map_.end(); ++it) | 336 it != death_map_.end(); ++it) |
337 (*output)[it->first] = it->second; | 337 (*output)[it->first] = it->second; |
338 } | 338 } |
339 | 339 |
340 // static | 340 // static |
341 void ThreadData::ResetAllThreadData() { | 341 void ThreadData::ResetAllThreadData() { |
342 ThreadData* my_list = ThreadData::current()->first(); | 342 ThreadData* my_list = ThreadData::current()->first(); |
343 | 343 |
344 for (ThreadData* thread_data = my_list; | 344 for (ThreadData* thread_data = my_list; |
345 thread_data; | 345 thread_data; |
346 thread_data = thread_data->next()) | 346 thread_data = thread_data->next()) |
347 thread_data->Reset(); | 347 thread_data->Reset(); |
348 } | 348 } |
349 | 349 |
350 void ThreadData::Reset() { | 350 void ThreadData::Reset() { |
351 AutoLock lock(lock_); | 351 base::AutoLock lock(lock_); |
352 for (DeathMap::iterator it = death_map_.begin(); | 352 for (DeathMap::iterator it = death_map_.begin(); |
353 it != death_map_.end(); ++it) | 353 it != death_map_.end(); ++it) |
354 it->second.Clear(); | 354 it->second.Clear(); |
355 for (BirthMap::iterator it = birth_map_.begin(); | 355 for (BirthMap::iterator it = birth_map_.begin(); |
356 it != birth_map_.end(); ++it) | 356 it != birth_map_.end(); ++it) |
357 it->second->Clear(); | 357 it->second->Clear(); |
358 } | 358 } |
359 | 359 |
360 #ifdef OS_WIN | 360 #ifdef OS_WIN |
361 // A class used to count down which is accessed by several threads. This is | 361 // A class used to count down which is accessed by several threads. This is |
362 // used to make sure RunOnAllThreads() actually runs a task on the expected | 362 // used to make sure RunOnAllThreads() actually runs a task on the expected |
363 // count of threads. | 363 // count of threads. |
364 class ThreadData::ThreadSafeDownCounter { | 364 class ThreadData::ThreadSafeDownCounter { |
365 public: | 365 public: |
366 // Constructor sets the count, once and for all. | 366 // Constructor sets the count, once and for all. |
367 explicit ThreadSafeDownCounter(size_t count); | 367 explicit ThreadSafeDownCounter(size_t count); |
368 | 368 |
369 // Decrement the count, and return true if we hit zero. Also delete this | 369 // Decrement the count, and return true if we hit zero. Also delete this |
370 // instance automatically when we hit zero. | 370 // instance automatically when we hit zero. |
371 bool LastCaller(); | 371 bool LastCaller(); |
372 | 372 |
373 private: | 373 private: |
374 size_t remaining_count_; | 374 size_t remaining_count_; |
375 Lock lock_; // protect access to remaining_count_. | 375 base::Lock lock_; // protect access to remaining_count_. |
376 }; | 376 }; |
377 | 377 |
378 ThreadData::ThreadSafeDownCounter::ThreadSafeDownCounter(size_t count) | 378 ThreadData::ThreadSafeDownCounter::ThreadSafeDownCounter(size_t count) |
379 : remaining_count_(count) { | 379 : remaining_count_(count) { |
380 DCHECK_GT(remaining_count_, 0u); | 380 DCHECK_GT(remaining_count_, 0u); |
381 } | 381 } |
382 | 382 |
383 bool ThreadData::ThreadSafeDownCounter::LastCaller() { | 383 bool ThreadData::ThreadSafeDownCounter::LastCaller() { |
384 { | 384 { |
385 AutoLock lock(lock_); | 385 base::AutoLock lock(lock_); |
386 if (--remaining_count_) | 386 if (--remaining_count_) |
387 return false; | 387 return false; |
388 } // Release lock, so we can delete everything in this instance. | 388 } // Release lock, so we can delete everything in this instance. |
389 delete this; | 389 delete this; |
390 return true; | 390 return true; |
391 } | 391 } |
392 | 392 |
393 // A Task class that runs a static method supplied, and checks to see if this | 393 // A Task class that runs a static method supplied, and checks to see if this |
394 // is the last tasks instance (on last thread) that will run the method. | 394 // is the last tasks instance (on last thread) that will run the method. |
395 // IF this is the last run, then the supplied event is signalled. | 395 // IF this is the last run, then the supplied event is signalled. |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
454 } | 454 } |
455 #endif | 455 #endif |
456 | 456 |
457 // static | 457 // static |
458 bool ThreadData::StartTracking(bool status) { | 458 bool ThreadData::StartTracking(bool status) { |
459 #ifndef TRACK_ALL_TASK_OBJECTS | 459 #ifndef TRACK_ALL_TASK_OBJECTS |
460 return false; // Not compiled in. | 460 return false; // Not compiled in. |
461 #endif | 461 #endif |
462 | 462 |
463 if (!status) { | 463 if (!status) { |
464 AutoLock lock(list_lock_); | 464 base::AutoLock lock(list_lock_); |
465 DCHECK(status_ == ACTIVE || status_ == SHUTDOWN); | 465 DCHECK(status_ == ACTIVE || status_ == SHUTDOWN); |
466 status_ = SHUTDOWN; | 466 status_ = SHUTDOWN; |
467 return true; | 467 return true; |
468 } | 468 } |
469 AutoLock lock(list_lock_); | 469 base::AutoLock lock(list_lock_); |
470 DCHECK(status_ == UNINITIALIZED); | 470 DCHECK(status_ == UNINITIALIZED); |
471 CHECK(tls_index_.Initialize(NULL)); | 471 CHECK(tls_index_.Initialize(NULL)); |
472 status_ = ACTIVE; | 472 status_ = ACTIVE; |
473 return true; | 473 return true; |
474 } | 474 } |
475 | 475 |
476 // static | 476 // static |
477 bool ThreadData::IsActive() { | 477 bool ThreadData::IsActive() { |
478 return status_ == ACTIVE; | 478 return status_ == ACTIVE; |
479 } | 479 } |
(...skipping 17 matching lines...) Expand all Loading... |
497 } | 497 } |
498 #endif | 498 #endif |
499 | 499 |
500 // static | 500 // static |
501 void ThreadData::ShutdownSingleThreadedCleanup() { | 501 void ThreadData::ShutdownSingleThreadedCleanup() { |
502 // We must be single threaded... but be careful anyway. | 502 // We must be single threaded... but be careful anyway. |
503 if (!StartTracking(false)) | 503 if (!StartTracking(false)) |
504 return; | 504 return; |
505 ThreadData* thread_data_list; | 505 ThreadData* thread_data_list; |
506 { | 506 { |
507 AutoLock lock(list_lock_); | 507 base::AutoLock lock(list_lock_); |
508 thread_data_list = first_; | 508 thread_data_list = first_; |
509 first_ = NULL; | 509 first_ = NULL; |
510 } | 510 } |
511 | 511 |
512 while (thread_data_list) { | 512 while (thread_data_list) { |
513 ThreadData* next_thread_data = thread_data_list; | 513 ThreadData* next_thread_data = thread_data_list; |
514 thread_data_list = thread_data_list->next(); | 514 thread_data_list = thread_data_list->next(); |
515 | 515 |
516 for (BirthMap::iterator it = next_thread_data->birth_map_.begin(); | 516 for (BirthMap::iterator it = next_thread_data->birth_map_.begin(); |
517 next_thread_data->birth_map_.end() != it; ++it) | 517 next_thread_data->birth_map_.end() != it; ++it) |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
607 } | 607 } |
608 | 608 |
609 void DataCollector::Append(const ThreadData& thread_data) { | 609 void DataCollector::Append(const ThreadData& thread_data) { |
610 // Get copy of data (which is done under ThreadData's lock). | 610 // Get copy of data (which is done under ThreadData's lock). |
611 ThreadData::BirthMap birth_map; | 611 ThreadData::BirthMap birth_map; |
612 thread_data.SnapshotBirthMap(&birth_map); | 612 thread_data.SnapshotBirthMap(&birth_map); |
613 ThreadData::DeathMap death_map; | 613 ThreadData::DeathMap death_map; |
614 thread_data.SnapshotDeathMap(&death_map); | 614 thread_data.SnapshotDeathMap(&death_map); |
615 | 615 |
616 // Use our lock to protect our accumulation activity. | 616 // Use our lock to protect our accumulation activity. |
617 AutoLock lock(accumulation_lock_); | 617 base::AutoLock lock(accumulation_lock_); |
618 | 618 |
619 DCHECK(count_of_contributing_threads_); | 619 DCHECK(count_of_contributing_threads_); |
620 | 620 |
621 for (ThreadData::DeathMap::const_iterator it = death_map.begin(); | 621 for (ThreadData::DeathMap::const_iterator it = death_map.begin(); |
622 it != death_map.end(); ++it) { | 622 it != death_map.end(); ++it) { |
623 collection_.push_back(Snapshot(*it->first, thread_data, it->second)); | 623 collection_.push_back(Snapshot(*it->first, thread_data, it->second)); |
624 global_birth_count_[it->first] -= it->first->birth_count(); | 624 global_birth_count_[it->first] -= it->first->birth_count(); |
625 } | 625 } |
626 | 626 |
627 for (ThreadData::BirthMap::const_iterator it = birth_map.begin(); | 627 for (ThreadData::BirthMap::const_iterator it = birth_map.begin(); |
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1048 (combined_selectors_ & BIRTH_THREAD) ? "*" : | 1048 (combined_selectors_ & BIRTH_THREAD) ? "*" : |
1049 sample.birth().birth_thread()->ThreadName().c_str(), | 1049 sample.birth().birth_thread()->ThreadName().c_str(), |
1050 (combined_selectors_ & DEATH_THREAD) ? "*" : | 1050 (combined_selectors_ & DEATH_THREAD) ? "*" : |
1051 sample.DeathThreadName().c_str()); | 1051 sample.DeathThreadName().c_str()); |
1052 sample.birth().location().Write(!(combined_selectors_ & BIRTH_FILE), | 1052 sample.birth().location().Write(!(combined_selectors_ & BIRTH_FILE), |
1053 !(combined_selectors_ & BIRTH_FUNCTION), | 1053 !(combined_selectors_ & BIRTH_FUNCTION), |
1054 output); | 1054 output); |
1055 } | 1055 } |
1056 | 1056 |
1057 } // namespace tracked_objects | 1057 } // namespace tracked_objects |
OLD | NEW |