Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(155)

Side by Side Diff: base/tracked_objects.cc

Issue 8567007: Use leaky lazy instance for master lock in profiler (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/tracked_objects.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « base/tracked_objects.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698