| OLD | NEW | 
|    1 // Copyright 2014 The Chromium Authors. All rights reserved. |    1 // Copyright 2014 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/threading/thread_local_storage.h" |    5 #include "base/threading/thread_local_storage.h" | 
|    6  |    6  | 
|    7 #include "base/atomicops.h" |    7 #include "base/atomicops.h" | 
|    8 #include "base/lazy_instance.h" |  | 
|    9 #include "base/logging.h" |    8 #include "base/logging.h" | 
|   10 #include "base/synchronization/lock.h" |    9 #include "base/synchronization/lock.h" | 
|   11 #include "build/build_config.h" |   10 #include "build/build_config.h" | 
|   12  |   11  | 
|   13 using base::internal::PlatformThreadLocalStorage; |   12 using base::internal::PlatformThreadLocalStorage; | 
|   14  |   13  | 
|   15 // Chrome Thread Local Storage (TLS) |   14 // Chrome Thread Local Storage (TLS) | 
|   16 // |   15 // | 
|   17 // This TLS system allows Chrome to use a single OS level TLS slot process-wide, |   16 // This TLS system allows Chrome to use a single OS level TLS slot process-wide, | 
|   18 // and allows us to control the slot limits instead of being at the mercy of the |   17 // and allows us to control the slot limits instead of being at the mercy of the | 
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   83   TlsStatus status; |   82   TlsStatus status; | 
|   84   base::ThreadLocalStorage::TLSDestructorFunc destructor; |   83   base::ThreadLocalStorage::TLSDestructorFunc destructor; | 
|   85   uint32_t version; |   84   uint32_t version; | 
|   86 }; |   85 }; | 
|   87  |   86  | 
|   88 struct TlsVectorEntry { |   87 struct TlsVectorEntry { | 
|   89   void* data; |   88   void* data; | 
|   90   uint32_t version; |   89   uint32_t version; | 
|   91 }; |   90 }; | 
|   92  |   91  | 
|   93 // This LazyInstance isn't needed until after we've constructed the per-thread |   92 // This lock isn't needed until after we've constructed the per-thread TLS | 
|   94 // TLS vector, so it's safe to use. |   93 // vector, so it's safe to use. | 
|   95 base::LazyInstance<base::Lock>::Leaky g_tls_metadata_lock; |   94 base::Lock* GetTLSMetadataLock() { | 
 |   95   static auto lock = new base::Lock(); | 
 |   96   return lock; | 
 |   97 } | 
|   96 TlsMetadata g_tls_metadata[kThreadLocalStorageSize]; |   98 TlsMetadata g_tls_metadata[kThreadLocalStorageSize]; | 
|   97 size_t g_last_assigned_slot = 0; |   99 size_t g_last_assigned_slot = 0; | 
|   98  |  100  | 
|   99 // The maximum number of times to try to clear slots by calling destructors. |  101 // The maximum number of times to try to clear slots by calling destructors. | 
|  100 // Use pthread naming convention for clarity. |  102 // Use pthread naming convention for clarity. | 
|  101 constexpr int kMaxDestructorIterations = kThreadLocalStorageSize; |  103 constexpr int kMaxDestructorIterations = kThreadLocalStorageSize; | 
|  102  |  104  | 
|  103 // This function is called to initialize our entire Chromium TLS system. |  105 // This function is called to initialize our entire Chromium TLS system. | 
|  104 // It may be called very early, and we need to complete most all of the setup |  106 // It may be called very early, and we need to complete most all of the setup | 
|  105 // (initialization) before calling *any* memory allocator functions, which may |  107 // (initialization) before calling *any* memory allocator functions, which may | 
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  175   memcpy(stack_allocated_tls_data, tls_data, sizeof(stack_allocated_tls_data)); |  177   memcpy(stack_allocated_tls_data, tls_data, sizeof(stack_allocated_tls_data)); | 
|  176   // Ensure that any re-entrant calls change the temp version. |  178   // Ensure that any re-entrant calls change the temp version. | 
|  177   PlatformThreadLocalStorage::TLSKey key = |  179   PlatformThreadLocalStorage::TLSKey key = | 
|  178       base::subtle::NoBarrier_Load(&g_native_tls_key); |  180       base::subtle::NoBarrier_Load(&g_native_tls_key); | 
|  179   PlatformThreadLocalStorage::SetTLSValue(key, stack_allocated_tls_data); |  181   PlatformThreadLocalStorage::SetTLSValue(key, stack_allocated_tls_data); | 
|  180   delete[] tls_data;  // Our last dependence on an allocator. |  182   delete[] tls_data;  // Our last dependence on an allocator. | 
|  181  |  183  | 
|  182   // Snapshot the TLS Metadata so we don't have to lock on every access. |  184   // Snapshot the TLS Metadata so we don't have to lock on every access. | 
|  183   TlsMetadata tls_metadata[kThreadLocalStorageSize]; |  185   TlsMetadata tls_metadata[kThreadLocalStorageSize]; | 
|  184   { |  186   { | 
|  185     base::AutoLock auto_lock(g_tls_metadata_lock.Get()); |  187     base::AutoLock auto_lock(*GetTLSMetadataLock()); | 
|  186     memcpy(tls_metadata, g_tls_metadata, sizeof(g_tls_metadata)); |  188     memcpy(tls_metadata, g_tls_metadata, sizeof(g_tls_metadata)); | 
|  187   } |  189   } | 
|  188  |  190  | 
|  189   int remaining_attempts = kMaxDestructorIterations; |  191   int remaining_attempts = kMaxDestructorIterations; | 
|  190   bool need_to_scan_destructors = true; |  192   bool need_to_scan_destructors = true; | 
|  191   while (need_to_scan_destructors) { |  193   while (need_to_scan_destructors) { | 
|  192     need_to_scan_destructors = false; |  194     need_to_scan_destructors = false; | 
|  193     // Try to destroy the first-created-slot (which is slot 1) in our last |  195     // Try to destroy the first-created-slot (which is slot 1) in our last | 
|  194     // destructor call. That user was able to function, and define a slot with |  196     // destructor call. That user was able to function, and define a slot with | 
|  195     // no other services running, so perhaps it is a basic service (like an |  197     // no other services running, so perhaps it is a basic service (like an | 
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  254       base::subtle::NoBarrier_Load(&g_native_tls_key); |  256       base::subtle::NoBarrier_Load(&g_native_tls_key); | 
|  255   if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES || |  257   if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES || | 
|  256       !PlatformThreadLocalStorage::GetTLSValue(key)) { |  258       !PlatformThreadLocalStorage::GetTLSValue(key)) { | 
|  257     ConstructTlsVector(); |  259     ConstructTlsVector(); | 
|  258   } |  260   } | 
|  259  |  261  | 
|  260   // Grab a new slot. |  262   // Grab a new slot. | 
|  261   slot_ = kInvalidSlotValue; |  263   slot_ = kInvalidSlotValue; | 
|  262   version_ = 0; |  264   version_ = 0; | 
|  263   { |  265   { | 
|  264     base::AutoLock auto_lock(g_tls_metadata_lock.Get()); |  266     base::AutoLock auto_lock(*GetTLSMetadataLock()); | 
|  265     for (int i = 0; i < kThreadLocalStorageSize; ++i) { |  267     for (int i = 0; i < kThreadLocalStorageSize; ++i) { | 
|  266       // Tracking the last assigned slot is an attempt to find the next |  268       // Tracking the last assigned slot is an attempt to find the next | 
|  267       // available slot within one iteration. Under normal usage, slots remain |  269       // available slot within one iteration. Under normal usage, slots remain | 
|  268       // in use for the lifetime of the process (otherwise before we reclaimed |  270       // in use for the lifetime of the process (otherwise before we reclaimed | 
|  269       // slots, we would have run out of slots). This makes it highly likely the |  271       // slots, we would have run out of slots). This makes it highly likely the | 
|  270       // next slot is going to be a free slot. |  272       // next slot is going to be a free slot. | 
|  271       size_t slot_candidate = |  273       size_t slot_candidate = | 
|  272           (g_last_assigned_slot + 1 + i) % kThreadLocalStorageSize; |  274           (g_last_assigned_slot + 1 + i) % kThreadLocalStorageSize; | 
|  273       if (g_tls_metadata[slot_candidate].status == TlsStatus::FREE) { |  275       if (g_tls_metadata[slot_candidate].status == TlsStatus::FREE) { | 
|  274         g_tls_metadata[slot_candidate].status = TlsStatus::IN_USE; |  276         g_tls_metadata[slot_candidate].status = TlsStatus::IN_USE; | 
|  275         g_tls_metadata[slot_candidate].destructor = destructor; |  277         g_tls_metadata[slot_candidate].destructor = destructor; | 
|  276         g_last_assigned_slot = slot_candidate; |  278         g_last_assigned_slot = slot_candidate; | 
|  277         slot_ = slot_candidate; |  279         slot_ = slot_candidate; | 
|  278         version_ = g_tls_metadata[slot_candidate].version; |  280         version_ = g_tls_metadata[slot_candidate].version; | 
|  279         break; |  281         break; | 
|  280       } |  282       } | 
|  281     } |  283     } | 
|  282   } |  284   } | 
|  283   CHECK_NE(slot_, kInvalidSlotValue); |  285   CHECK_NE(slot_, kInvalidSlotValue); | 
|  284   CHECK_LT(slot_, kThreadLocalStorageSize); |  286   CHECK_LT(slot_, kThreadLocalStorageSize); | 
|  285  |  287  | 
|  286   // Setup our destructor. |  288   // Setup our destructor. | 
|  287   base::subtle::Release_Store(&initialized_, 1); |  289   base::subtle::Release_Store(&initialized_, 1); | 
|  288 } |  290 } | 
|  289  |  291  | 
|  290 void ThreadLocalStorage::StaticSlot::Free() { |  292 void ThreadLocalStorage::StaticSlot::Free() { | 
|  291   DCHECK_NE(slot_, kInvalidSlotValue); |  293   DCHECK_NE(slot_, kInvalidSlotValue); | 
|  292   DCHECK_LT(slot_, kThreadLocalStorageSize); |  294   DCHECK_LT(slot_, kThreadLocalStorageSize); | 
|  293   { |  295   { | 
|  294     base::AutoLock auto_lock(g_tls_metadata_lock.Get()); |  296     base::AutoLock auto_lock(*GetTLSMetadataLock()); | 
|  295     g_tls_metadata[slot_].status = TlsStatus::FREE; |  297     g_tls_metadata[slot_].status = TlsStatus::FREE; | 
|  296     g_tls_metadata[slot_].destructor = nullptr; |  298     g_tls_metadata[slot_].destructor = nullptr; | 
|  297     ++(g_tls_metadata[slot_].version); |  299     ++(g_tls_metadata[slot_].version); | 
|  298   } |  300   } | 
|  299   slot_ = kInvalidSlotValue; |  301   slot_ = kInvalidSlotValue; | 
|  300   base::subtle::Release_Store(&initialized_, 0); |  302   base::subtle::Release_Store(&initialized_, 0); | 
|  301 } |  303 } | 
|  302  |  304  | 
|  303 void* ThreadLocalStorage::StaticSlot::Get() const { |  305 void* ThreadLocalStorage::StaticSlot::Get() const { | 
|  304   TlsVectorEntry* tls_data = static_cast<TlsVectorEntry*>( |  306   TlsVectorEntry* tls_data = static_cast<TlsVectorEntry*>( | 
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  336  |  338  | 
|  337 void* ThreadLocalStorage::Slot::Get() const { |  339 void* ThreadLocalStorage::Slot::Get() const { | 
|  338   return tls_slot_.Get(); |  340   return tls_slot_.Get(); | 
|  339 } |  341 } | 
|  340  |  342  | 
|  341 void ThreadLocalStorage::Slot::Set(void* value) { |  343 void ThreadLocalStorage::Slot::Set(void* value) { | 
|  342   tls_slot_.Set(value); |  344   tls_slot_.Set(value); | 
|  343 } |  345 } | 
|  344  |  346  | 
|  345 }  // namespace base |  347 }  // namespace base | 
| OLD | NEW |