| 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 |