| 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 | 
|---|