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 |