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 |