| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 // static | 158 // static |
| 159 int ThreadData::incarnation_counter_ = 0; | 159 int ThreadData::incarnation_counter_ = 0; |
| 160 | 160 |
| 161 // static | 161 // static |
| 162 ThreadData* ThreadData::all_thread_data_list_head_ = NULL; | 162 ThreadData* ThreadData::all_thread_data_list_head_ = NULL; |
| 163 | 163 |
| 164 // static | 164 // static |
| 165 ThreadData::ThreadDataPool* ThreadData::unregistered_thread_data_pool_ = NULL; | 165 ThreadData::ThreadDataPool* ThreadData::unregistered_thread_data_pool_ = NULL; |
| 166 | 166 |
| 167 // static | 167 // static |
| 168 base::Lock* ThreadData::list_lock_; | 168 base::LazyInstance<base::Lock, |
| 169 base::LeakyLazyInstanceTraits<base::Lock> > |
| 170 ThreadData::list_lock_(base::LINKER_INITIALIZED); |
| 169 | 171 |
| 170 // static | 172 // static |
| 171 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; | 173 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; |
| 172 | 174 |
| 173 ThreadData::ThreadData(const std::string& suggested_name) | 175 ThreadData::ThreadData(const std::string& suggested_name) |
| 174 : incarnation_count_for_pool_(-1), | 176 : incarnation_count_for_pool_(-1), |
| 175 next_(NULL), | 177 next_(NULL), |
| 176 is_a_worker_thread_(false) { | 178 is_a_worker_thread_(false) { |
| 177 DCHECK_GE(suggested_name.size(), 0u); | 179 DCHECK_GE(suggested_name.size(), 0u); |
| 178 thread_name_ = suggested_name; | 180 thread_name_ = suggested_name; |
| 179 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. | 181 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. |
| 180 } | 182 } |
| 181 | 183 |
| 182 ThreadData::ThreadData() | 184 ThreadData::ThreadData() |
| 183 : incarnation_count_for_pool_(-1), | 185 : incarnation_count_for_pool_(-1), |
| 184 next_(NULL), | 186 next_(NULL), |
| 185 is_a_worker_thread_(true) { | 187 is_a_worker_thread_(true) { |
| 186 int thread_number; | 188 int thread_number; |
| 187 { | 189 { |
| 188 base::AutoLock lock(*list_lock_); | 190 base::AutoLock lock(*list_lock_.Pointer()); |
| 189 thread_number = ++thread_number_counter_; | 191 thread_number = ++thread_number_counter_; |
| 190 } | 192 } |
| 191 base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number); | 193 base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number); |
| 192 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. | 194 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. |
| 193 } | 195 } |
| 194 | 196 |
| 195 ThreadData::~ThreadData() {} | 197 ThreadData::~ThreadData() {} |
| 196 | 198 |
| 197 void ThreadData::PushToHeadOfList() { | 199 void ThreadData::PushToHeadOfList() { |
| 198 DCHECK(!next_); | 200 DCHECK(!next_); |
| 199 base::AutoLock lock(*list_lock_); | 201 base::AutoLock lock(*list_lock_.Pointer()); |
| 200 incarnation_count_for_pool_ = incarnation_counter_; | 202 incarnation_count_for_pool_ = incarnation_counter_; |
| 201 next_ = all_thread_data_list_head_; | 203 next_ = all_thread_data_list_head_; |
| 202 all_thread_data_list_head_ = this; | 204 all_thread_data_list_head_ = this; |
| 203 } | 205 } |
| 204 | 206 |
| 205 // static | 207 // static |
| 206 void ThreadData::InitializeThreadContext(const std::string& suggested_name) { | 208 void ThreadData::InitializeThreadContext(const std::string& suggested_name) { |
| 207 if (!Initialize()) // Always initialize if needed. | 209 if (!Initialize()) // Always initialize if needed. |
| 208 return; | 210 return; |
| 209 ThreadData* current_thread_data = | 211 ThreadData* current_thread_data = |
| 210 reinterpret_cast<ThreadData*>(tls_index_.Get()); | 212 reinterpret_cast<ThreadData*>(tls_index_.Get()); |
| 211 if (current_thread_data) | 213 if (current_thread_data) |
| 212 return; // Browser tests instigate this. | 214 return; // Browser tests instigate this. |
| 213 current_thread_data = new ThreadData(suggested_name); | 215 current_thread_data = new ThreadData(suggested_name); |
| 214 tls_index_.Set(current_thread_data); | 216 tls_index_.Set(current_thread_data); |
| 215 } | 217 } |
| 216 | 218 |
| 217 // static | 219 // static |
| 218 ThreadData* ThreadData::Get() { | 220 ThreadData* ThreadData::Get() { |
| 219 if (!tls_index_.initialized()) | 221 if (!tls_index_.initialized()) |
| 220 return NULL; // For unittests only. | 222 return NULL; // For unittests only. |
| 221 ThreadData* registered = reinterpret_cast<ThreadData*>(tls_index_.Get()); | 223 ThreadData* registered = reinterpret_cast<ThreadData*>(tls_index_.Get()); |
| 222 if (registered) | 224 if (registered) |
| 223 return registered; | 225 return registered; |
| 224 | 226 |
| 225 // We must be a worker thread, since we didn't pre-register. | 227 // We must be a worker thread, since we didn't pre-register. |
| 226 ThreadData* worker_thread_data = NULL; | 228 ThreadData* worker_thread_data = NULL; |
| 227 { | 229 { |
| 228 base::AutoLock lock(*list_lock_); | 230 base::AutoLock lock(*list_lock_.Pointer()); |
| 229 if (!unregistered_thread_data_pool_->empty()) { | 231 if (unregistered_thread_data_pool_ && |
| 232 !unregistered_thread_data_pool_->empty()) { |
| 230 worker_thread_data = | 233 worker_thread_data = |
| 231 const_cast<ThreadData*>(unregistered_thread_data_pool_->top()); | 234 const_cast<ThreadData*>(unregistered_thread_data_pool_->top()); |
| 232 unregistered_thread_data_pool_->pop(); | 235 unregistered_thread_data_pool_->pop(); |
| 233 } | 236 } |
| 234 } | 237 } |
| 235 | 238 |
| 236 // If we can't find a previously used instance, then we have to create one. | 239 // If we can't find a previously used instance, then we have to create one. |
| 237 if (!worker_thread_data) | 240 if (!worker_thread_data) |
| 238 worker_thread_data = new ThreadData(); | 241 worker_thread_data = new ThreadData(); |
| 239 | 242 |
| 240 tls_index_.Set(worker_thread_data); | 243 tls_index_.Set(worker_thread_data); |
| 241 return worker_thread_data; | 244 return worker_thread_data; |
| 242 } | 245 } |
| 243 | 246 |
| 244 // static | 247 // static |
| 245 void ThreadData::OnThreadTermination(void* thread_data) { | 248 void ThreadData::OnThreadTermination(void* thread_data) { |
| 246 if (!kTrackAllTaskObjects) | 249 if (!kTrackAllTaskObjects) |
| 247 return; // Not compiled in. | 250 return; // Not compiled in. |
| 248 if (!thread_data) | 251 if (!thread_data) |
| 249 return; | 252 return; |
| 250 reinterpret_cast<ThreadData*>(thread_data)->OnThreadTerminationCleanup(); | 253 reinterpret_cast<ThreadData*>(thread_data)->OnThreadTerminationCleanup(); |
| 251 } | 254 } |
| 252 | 255 |
| 253 void ThreadData::OnThreadTerminationCleanup() const { | 256 void ThreadData::OnThreadTerminationCleanup() const { |
| 254 if (!is_a_worker_thread_) | 257 if (!is_a_worker_thread_) |
| 255 return; | 258 return; |
| 256 base::AutoLock lock(*list_lock_); | 259 base::AutoLock lock(*list_lock_.Pointer()); |
| 257 if (incarnation_counter_ != incarnation_count_for_pool_) | 260 if (incarnation_counter_ != incarnation_count_for_pool_) |
| 258 return; // ThreadData was constructed in an earlier unit test. | 261 return; // ThreadData was constructed in an earlier unit test. |
| 259 | 262 |
| 260 // Handle case where we are in unit tests, and have become UNINITIALIZED. | 263 // Handle case where we are in unit tests, and have become UNINITIALIZED. |
| 261 // In that case, the pool might be NULL. We really should detect this via the | 264 // In that case, the pool might be NULL. We really should detect this via the |
| 262 // incarnation_counter_, but this call is rarely made, so we can afford to | 265 // incarnation_counter_, but this call is rarely made, so we can afford to |
| 263 // code defensively. | 266 // code defensively. |
| 264 if (unregistered_thread_data_pool_) | 267 if (!unregistered_thread_data_pool_) |
| 265 unregistered_thread_data_pool_->push(this); | 268 unregistered_thread_data_pool_ = new ThreadDataPool; |
| 269 unregistered_thread_data_pool_->push(this); |
| 266 } | 270 } |
| 267 | 271 |
| 268 // static | 272 // static |
| 269 void ThreadData::WriteHTML(const std::string& query, std::string* output) { | 273 void ThreadData::WriteHTML(const std::string& query, std::string* output) { |
| 270 if (status_ == UNINITIALIZED) | 274 if (status_ == UNINITIALIZED) |
| 271 return; // Not yet initialized. | 275 return; // Not yet initialized. |
| 272 | 276 |
| 273 DataCollector collected_data; // Gather data. | 277 DataCollector collected_data; // Gather data. |
| 274 collected_data.AddListOfLivingObjects(); // Add births that are still alive. | 278 collected_data.AddListOfLivingObjects(); // Add births that are still alive. |
| 275 | 279 |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 528 | 532 |
| 529 DurationInt queue_duration = 0; | 533 DurationInt queue_duration = 0; |
| 530 DurationInt run_duration = (end_of_run - start_of_run).InMilliseconds(); | 534 DurationInt run_duration = (end_of_run - start_of_run).InMilliseconds(); |
| 531 current_thread_data->TallyADeath(*birth, queue_duration, run_duration); | 535 current_thread_data->TallyADeath(*birth, queue_duration, run_duration); |
| 532 } | 536 } |
| 533 | 537 |
| 534 | 538 |
| 535 | 539 |
| 536 // static | 540 // static |
| 537 ThreadData* ThreadData::first() { | 541 ThreadData* ThreadData::first() { |
| 538 base::AutoLock lock(*list_lock_); | 542 base::AutoLock lock(*list_lock_.Pointer()); |
| 539 return all_thread_data_list_head_; | 543 return all_thread_data_list_head_; |
| 540 } | 544 } |
| 541 | 545 |
| 542 // This may be called from another thread. | 546 // This may be called from another thread. |
| 543 void ThreadData::SnapshotBirthMap(BirthMap *output) const { | 547 void ThreadData::SnapshotBirthMap(BirthMap *output) const { |
| 544 base::AutoLock lock(lock_); | 548 base::AutoLock lock(lock_); |
| 545 for (BirthMap::const_iterator it = birth_map_.begin(); | 549 for (BirthMap::const_iterator it = birth_map_.begin(); |
| 546 it != birth_map_.end(); ++it) | 550 it != birth_map_.end(); ++it) |
| 547 (*output)[it->first] = it->second; | 551 (*output)[it->first] = it->second; |
| 548 } | 552 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 581 if (status_ != UNINITIALIZED) | 585 if (status_ != UNINITIALIZED) |
| 582 return true; | 586 return true; |
| 583 // Initialize all leaking constants that are difficult to toggle in and out | 587 // Initialize all leaking constants that are difficult to toggle in and out |
| 584 // of existance. | 588 // of existance. |
| 585 // First call must be made when single threaded at startup. | 589 // First call must be made when single threaded at startup. |
| 586 // Perform the "real" TLS initialization now, and leave it intact through | 590 // Perform the "real" TLS initialization now, and leave it intact through |
| 587 // process termination. | 591 // process termination. |
| 588 if (!tls_index_.initialized()) // Testing may have initialized this. | 592 if (!tls_index_.initialized()) // Testing may have initialized this. |
| 589 tls_index_.Initialize(&ThreadData::OnThreadTermination); | 593 tls_index_.Initialize(&ThreadData::OnThreadTermination); |
| 590 DCHECK(tls_index_.initialized()); | 594 DCHECK(tls_index_.initialized()); |
| 591 ThreadDataPool* pool = new ThreadDataPool; | |
| 592 // TODO(jar): A linker initialized spin lock would be much safer than this | |
| 593 // allocation, which relies on being called while single threaded. | |
| 594 if (!list_lock_) // In case testing deleted this. | |
| 595 list_lock_ = new base::Lock; | |
| 596 status_ = kInitialStartupState; | 595 status_ = kInitialStartupState; |
| 597 | 596 |
| 598 base::AutoLock lock(*list_lock_); | 597 base::AutoLock lock(*list_lock_.Pointer()); |
| 599 DCHECK_EQ(unregistered_thread_data_pool_, | |
| 600 reinterpret_cast<ThreadDataPool*>(NULL)); | |
| 601 unregistered_thread_data_pool_ = pool; | |
| 602 ++incarnation_counter_; | 598 ++incarnation_counter_; |
| 603 return true; | 599 return true; |
| 604 } | 600 } |
| 605 | 601 |
| 606 // static | 602 // static |
| 607 bool ThreadData::InitializeAndSetTrackingStatus(bool status) { | 603 bool ThreadData::InitializeAndSetTrackingStatus(bool status) { |
| 608 if (!Initialize()) // No-op if already initialized. | 604 if (!Initialize()) // No-op if already initialized. |
| 609 return false; // Not compiled in. | 605 return false; // Not compiled in. |
| 610 | 606 |
| 611 status_ = status ? ACTIVE : DEACTIVATED; | 607 status_ = status ? ACTIVE : DEACTIVATED; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 637 // static | 633 // static |
| 638 void ThreadData::ShutdownSingleThreadedCleanup(bool leak) { | 634 void ThreadData::ShutdownSingleThreadedCleanup(bool leak) { |
| 639 // This is only called from test code, where we need to cleanup so that | 635 // This is only called from test code, where we need to cleanup so that |
| 640 // additional tests can be run. | 636 // additional tests can be run. |
| 641 // We must be single threaded... but be careful anyway. | 637 // We must be single threaded... but be careful anyway. |
| 642 if (!InitializeAndSetTrackingStatus(false)) | 638 if (!InitializeAndSetTrackingStatus(false)) |
| 643 return; | 639 return; |
| 644 ThreadData* thread_data_list; | 640 ThreadData* thread_data_list; |
| 645 ThreadDataPool* final_pool; | 641 ThreadDataPool* final_pool; |
| 646 { | 642 { |
| 647 base::AutoLock lock(*list_lock_); | 643 base::AutoLock lock(*list_lock_.Pointer()); |
| 648 thread_data_list = all_thread_data_list_head_; | 644 thread_data_list = all_thread_data_list_head_; |
| 649 all_thread_data_list_head_ = NULL; | 645 all_thread_data_list_head_ = NULL; |
| 650 final_pool = unregistered_thread_data_pool_; | 646 final_pool = unregistered_thread_data_pool_; |
| 651 unregistered_thread_data_pool_ = NULL; | 647 unregistered_thread_data_pool_ = NULL; |
| 652 ++incarnation_counter_; | 648 ++incarnation_counter_; |
| 653 } | 649 } |
| 654 | 650 |
| 655 // Put most global static back in pristine shape. | 651 // Put most global static back in pristine shape. |
| 656 thread_number_counter_ = 0; | 652 thread_number_counter_ = 0; |
| 657 tls_index_.Set(NULL); | 653 tls_index_.Set(NULL); |
| (...skipping 599 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1257 (combined_selectors_ & BIRTH_THREAD) ? "*" : | 1253 (combined_selectors_ & BIRTH_THREAD) ? "*" : |
| 1258 sample.birth().birth_thread()->thread_name().c_str(), | 1254 sample.birth().birth_thread()->thread_name().c_str(), |
| 1259 (combined_selectors_ & DEATH_THREAD) ? "*" : | 1255 (combined_selectors_ & DEATH_THREAD) ? "*" : |
| 1260 sample.DeathThreadName().c_str()); | 1256 sample.DeathThreadName().c_str()); |
| 1261 sample.birth().location().Write(!(combined_selectors_ & BIRTH_FILE), | 1257 sample.birth().location().Write(!(combined_selectors_ & BIRTH_FILE), |
| 1262 !(combined_selectors_ & BIRTH_FUNCTION), | 1258 !(combined_selectors_ & BIRTH_FUNCTION), |
| 1263 output); | 1259 output); |
| 1264 } | 1260 } |
| 1265 | 1261 |
| 1266 } // namespace tracked_objects | 1262 } // namespace tracked_objects |
| OLD | NEW |