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

Side by Side Diff: base/tracked_objects.cc

Issue 1222123002: Fix a race in ThreadLocalStorage::StaticSlot::initialized which triggers a TSAN error. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix MSVC compile warning. Created 5 years, 5 months 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
« no previous file with comments | « base/tracked_objects.h ('k') | build/sanitizers/tsan_suppressions.cc » ('j') | 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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 <limits.h> 7 #include <limits.h>
8 #include <stdlib.h> 8 #include <stdlib.h>
9 9
10 #include "base/atomicops.h" 10 #include "base/atomicops.h"
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 ThreadData* ThreadData::all_thread_data_list_head_ = NULL; 303 ThreadData* ThreadData::all_thread_data_list_head_ = NULL;
304 304
305 // static 305 // static
306 ThreadData* ThreadData::first_retired_worker_ = NULL; 306 ThreadData* ThreadData::first_retired_worker_ = NULL;
307 307
308 // static 308 // static
309 base::LazyInstance<base::Lock>::Leaky 309 base::LazyInstance<base::Lock>::Leaky
310 ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER; 310 ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER;
311 311
312 // static 312 // static
313 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; 313 base::subtle::Atomic32 ThreadData::status_ = ThreadData::UNINITIALIZED;
314 314
315 ThreadData::ThreadData(const std::string& suggested_name) 315 ThreadData::ThreadData(const std::string& suggested_name)
316 : next_(NULL), 316 : next_(NULL),
317 next_retired_worker_(NULL), 317 next_retired_worker_(NULL),
318 worker_thread_number_(0), 318 worker_thread_number_(0),
319 incarnation_count_for_pool_(-1), 319 incarnation_count_for_pool_(-1),
320 current_stopwatch_(NULL) { 320 current_stopwatch_(NULL) {
321 DCHECK_GE(suggested_name.size(), 0u); 321 DCHECK_GE(suggested_name.size(), 0u);
322 thread_name_ = suggested_name; 322 thread_name_ = suggested_name;
323 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. 323 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_.
(...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after
685 } 685 }
686 } 686 }
687 687
688 static void OptionallyInitializeAlternateTimer() { 688 static void OptionallyInitializeAlternateTimer() {
689 NowFunction* alternate_time_source = GetAlternateTimeSource(); 689 NowFunction* alternate_time_source = GetAlternateTimeSource();
690 if (alternate_time_source) 690 if (alternate_time_source)
691 ThreadData::SetAlternateTimeSource(alternate_time_source); 691 ThreadData::SetAlternateTimeSource(alternate_time_source);
692 } 692 }
693 693
694 void ThreadData::Initialize() { 694 void ThreadData::Initialize() {
695 if (status_ >= DEACTIVATED) 695 if (base::subtle::Acquire_Load(&status_) >= DEACTIVATED)
696 return; // Someone else did the initialization. 696 return; // Someone else did the initialization.
697 // Due to racy lazy initialization in tests, we'll need to recheck status_ 697 // Due to racy lazy initialization in tests, we'll need to recheck status_
698 // after we acquire the lock. 698 // after we acquire the lock.
699 699
700 // Ensure that we don't double initialize tls. We are called when single 700 // Ensure that we don't double initialize tls. We are called when single
701 // threaded in the product, but some tests may be racy and lazy about our 701 // threaded in the product, but some tests may be racy and lazy about our
702 // initialization. 702 // initialization.
703 base::AutoLock lock(*list_lock_.Pointer()); 703 base::AutoLock lock(*list_lock_.Pointer());
704 if (status_ >= DEACTIVATED) 704 if (base::subtle::Acquire_Load(&status_) >= DEACTIVATED)
705 return; // Someone raced in here and beat us. 705 return; // Someone raced in here and beat us.
706 706
707 // Put an alternate timer in place if the environment calls for it, such as 707 // Put an alternate timer in place if the environment calls for it, such as
708 // for tracking TCMalloc allocations. This insertion is idempotent, so we 708 // for tracking TCMalloc allocations. This insertion is idempotent, so we
709 // don't mind if there is a race, and we'd prefer not to be in a lock while 709 // don't mind if there is a race, and we'd prefer not to be in a lock while
710 // doing this work. 710 // doing this work.
711 if (kAllowAlternateTimeSourceHandling) 711 if (kAllowAlternateTimeSourceHandling)
712 OptionallyInitializeAlternateTimer(); 712 OptionallyInitializeAlternateTimer();
713 713
714 // Perform the "real" TLS initialization now, and leave it intact through 714 // Perform the "real" TLS initialization now, and leave it intact through
715 // process termination. 715 // process termination.
716 if (!tls_index_.initialized()) { // Testing may have initialized this. 716 if (!tls_index_.initialized()) { // Testing may have initialized this.
717 DCHECK_EQ(status_, UNINITIALIZED); 717 DCHECK_EQ(base::subtle::NoBarrier_Load(&status_), UNINITIALIZED);
718 tls_index_.Initialize(&ThreadData::OnThreadTermination); 718 tls_index_.Initialize(&ThreadData::OnThreadTermination);
719 DCHECK(tls_index_.initialized()); 719 DCHECK(tls_index_.initialized());
720 } else { 720 } else {
721 // TLS was initialzed for us earlier. 721 // TLS was initialzed for us earlier.
722 DCHECK_EQ(status_, DORMANT_DURING_TESTS); 722 DCHECK_EQ(base::subtle::NoBarrier_Load(&status_), DORMANT_DURING_TESTS);
723 } 723 }
724 724
725 // Incarnation counter is only significant to testing, as it otherwise will 725 // Incarnation counter is only significant to testing, as it otherwise will
726 // never again change in this process. 726 // never again change in this process.
727 ++incarnation_counter_; 727 ++incarnation_counter_;
728 728
729 // The lock is not critical for setting status_, but it doesn't hurt. It also 729 // The lock is not critical for setting status_, but it doesn't hurt. It also
730 // ensures that if we have a racy initialization, that we'll bail as soon as 730 // ensures that if we have a racy initialization, that we'll bail as soon as
731 // we get the lock earlier in this method. 731 // we get the lock earlier in this method.
732 status_ = kInitialStartupState; 732 base::subtle::Release_Store(&status_, kInitialStartupState);
733 DCHECK(status_ != UNINITIALIZED); 733 DCHECK(base::subtle::NoBarrier_Load(&status_) != UNINITIALIZED);
734 } 734 }
735 735
736 // static 736 // static
737 void ThreadData::InitializeAndSetTrackingStatus(Status status) { 737 void ThreadData::InitializeAndSetTrackingStatus(Status status) {
738 DCHECK_GE(status, DEACTIVATED); 738 DCHECK_GE(status, DEACTIVATED);
739 DCHECK_LE(status, PROFILING_ACTIVE); 739 DCHECK_LE(status, PROFILING_ACTIVE);
740 740
741 Initialize(); // No-op if already initialized. 741 Initialize(); // No-op if already initialized.
742 742
743 if (status > DEACTIVATED) 743 if (status > DEACTIVATED)
744 status = PROFILING_ACTIVE; 744 status = PROFILING_ACTIVE;
745 status_ = status; 745 base::subtle::Release_Store(&status_, status);
746 } 746 }
747 747
748 // static 748 // static
749 ThreadData::Status ThreadData::status() { 749 ThreadData::Status ThreadData::status() {
750 return status_; 750 return static_cast<ThreadData::Status>(base::subtle::Acquire_Load(&status_));
751 } 751 }
752 752
753 // static 753 // static
754 bool ThreadData::TrackingStatus() { 754 bool ThreadData::TrackingStatus() {
755 return status_ > DEACTIVATED; 755 return base::subtle::Acquire_Load(&status_) > DEACTIVATED;
756 } 756 }
757 757
758 // static 758 // static
759 void ThreadData::SetAlternateTimeSource(NowFunction* now_function) { 759 void ThreadData::SetAlternateTimeSource(NowFunction* now_function) {
760 DCHECK(now_function); 760 DCHECK(now_function);
761 if (kAllowAlternateTimeSourceHandling) 761 if (kAllowAlternateTimeSourceHandling)
762 now_function_ = now_function; 762 now_function_ = now_function;
763 } 763 }
764 764
765 // static 765 // static
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
810 CHECK_GT(worker->worker_thread_number_, 0); 810 CHECK_GT(worker->worker_thread_number_, 0);
811 first_retired_worker_ = worker->next_retired_worker_; 811 first_retired_worker_ = worker->next_retired_worker_;
812 worker->next_retired_worker_ = NULL; 812 worker->next_retired_worker_ = NULL;
813 } 813 }
814 } 814 }
815 815
816 // Put most global static back in pristine shape. 816 // Put most global static back in pristine shape.
817 worker_thread_data_creation_count_ = 0; 817 worker_thread_data_creation_count_ = 0;
818 cleanup_count_ = 0; 818 cleanup_count_ = 0;
819 tls_index_.Set(NULL); 819 tls_index_.Set(NULL);
820 status_ = DORMANT_DURING_TESTS; // Almost UNINITIALIZED. 820 // Almost UNINITIALIZED.
821 base::subtle::Release_Store(&status_, DORMANT_DURING_TESTS);
821 822
822 // To avoid any chance of racing in unit tests, which is the only place we 823 // To avoid any chance of racing in unit tests, which is the only place we
823 // call this function, we may sometimes leak all the data structures we 824 // call this function, we may sometimes leak all the data structures we
824 // recovered, as they may still be in use on threads from prior tests! 825 // recovered, as they may still be in use on threads from prior tests!
825 if (leak) { 826 if (leak) {
826 ThreadData* thread_data = thread_data_list; 827 ThreadData* thread_data = thread_data_list;
827 while (thread_data) { 828 while (thread_data) {
828 ANNOTATE_LEAKING_OBJECT_PTR(thread_data); 829 ANNOTATE_LEAKING_OBJECT_PTR(thread_data);
829 thread_data = thread_data->next(); 830 thread_data = thread_data->next();
830 } 831 }
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
998 : process_id(base::GetCurrentProcId()) { 999 : process_id(base::GetCurrentProcId()) {
999 #else 1000 #else
1000 : process_id(base::kNullProcessId) { 1001 : process_id(base::kNullProcessId) {
1001 #endif 1002 #endif
1002 } 1003 }
1003 1004
1004 ProcessDataSnapshot::~ProcessDataSnapshot() { 1005 ProcessDataSnapshot::~ProcessDataSnapshot() {
1005 } 1006 }
1006 1007
1007 } // namespace tracked_objects 1008 } // namespace tracked_objects
OLDNEW
« no previous file with comments | « base/tracked_objects.h ('k') | build/sanitizers/tsan_suppressions.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698