1b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Copyright 2014 The Chromium Authors. All rights reserved. 2b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Use of this source code is governed by a BSD-style license that can be 3b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// found in the LICENSE file. 4b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 5b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/threading/thread_local_storage.h" 6b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 7b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/atomicops.h" 8b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/logging.h" 93a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli#include "base/synchronization/lock.h" 10cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#include "build/build_config.h" 11b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 12b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratusing base::internal::PlatformThreadLocalStorage; 13b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 143a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// Chrome Thread Local Storage (TLS) 153a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// 163a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// This TLS system allows Chrome to use a single OS level TLS slot process-wide, 173a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// and allows us to control the slot limits instead of being at the mercy of the 183a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// platform. To do this, Chrome TLS replicates an array commonly found in the OS 193a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// thread metadata. 203a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// 213a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// Overview: 223a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// 233a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// OS TLS Slots Per-Thread Per-Process Global 243a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// ... 253a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// [] Chrome TLS Array Chrome TLS Metadata 263a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// [] ----------> [][][][][ ][][][][] [][][][][ ][][][][] 273a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// [] | | 283a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// ... V V 293a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// Metadata Version Slot Information 303a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// Your Data! 313a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// 323a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// Using a single OS TLS slot, Chrome TLS allocates an array on demand for the 333a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// lifetime of each thread that requests Chrome TLS data. Each per-thread TLS 343a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// array matches the length of the per-process global metadata array. 353a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// 363a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// A per-process global TLS metadata array tracks information about each item in 373a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// the per-thread array: 383a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// * Status: Tracks if the slot is allocated or free to assign. 393a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// * Destructor: An optional destructor to call on thread destruction for that 403a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// specific slot. 413a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// * Version: Tracks the current version of the TLS slot. Each TLS slot 423a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// allocation is associated with a unique version number. 433a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// 443a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// Most OS TLS APIs guarantee that a newly allocated TLS slot is 453a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// initialized to 0 for all threads. The Chrome TLS system provides 463a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// this guarantee by tracking the version for each TLS slot here 473a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// on each per-thread Chrome TLS array entry. Threads that access 483a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// a slot with a mismatched version will receive 0 as their value. 493a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// The metadata version is incremented when the client frees a 503a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// slot. The per-thread metadata version is updated when a client 513a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// writes to the slot. This scheme allows for constant time 523a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// invalidation and avoids the need to iterate through each Chrome 533a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// TLS array to mark the slot as zero. 543a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// 553a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// Just like an OS TLS API, clients of the Chrome TLS are responsible for 563a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// managing any necessary lifetime of the data in their slots. The only 573a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// convenience provided is automatic destruction when a thread ends. If a client 583a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// frees a slot, that client is responsible for destroying the data in the slot. 593a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli 60b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace { 61b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// In order to make TLS destructors work, we need to keep around a function 62b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// pointer to the destructor for each slot. We keep this array of pointers in a 63b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// global (static) array. 64b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// We use the single OS-level TLS slot (giving us one pointer per thread) to 65b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// hold a pointer to a per-thread array (table) of slots that we allocate to 66b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Chromium consumers. 67b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 683a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// g_native_tls_key is the one native TLS that we use. It stores our table. 69b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratbase::subtle::Atomic32 g_native_tls_key = 70b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES; 71b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 723a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// The maximum number of slots in our thread local storage stack. 733a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelliconstexpr int kThreadLocalStorageSize = 256; 743a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelliconstexpr int kInvalidSlotValue = -1; 753a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli 763a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civellienum TlsStatus { 773a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli FREE, 783a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli IN_USE, 793a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli}; 803a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli 813a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civellistruct TlsMetadata { 823a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli TlsStatus status; 833a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli base::ThreadLocalStorage::TLSDestructorFunc destructor; 843a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli uint32_t version; 853a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli}; 86b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 873a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civellistruct TlsVectorEntry { 883a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli void* data; 893a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli uint32_t version; 903a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli}; 913a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli 923a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// This lock isn't needed until after we've constructed the per-thread TLS 933a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// vector, so it's safe to use. 943a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civellibase::Lock* GetTLSMetadataLock() { 953a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli static auto* lock = new base::Lock(); 963a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli return lock; 973a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli} 983a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay CivelliTlsMetadata g_tls_metadata[kThreadLocalStorageSize]; 993a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civellisize_t g_last_assigned_slot = 0; 100b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 101b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// The maximum number of times to try to clear slots by calling destructors. 102b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Use pthread naming convention for clarity. 1033a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelliconstexpr int kMaxDestructorIterations = kThreadLocalStorageSize; 104b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 105b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// This function is called to initialize our entire Chromium TLS system. 106b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// It may be called very early, and we need to complete most all of the setup 107b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// (initialization) before calling *any* memory allocator functions, which may 108b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// recursively depend on this initialization. 109b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// As a result, we use Atomics, and avoid anything (like a singleton) that might 110b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// require memory allocations. 1113a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay CivelliTlsVectorEntry* ConstructTlsVector() { 112b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::TLSKey key = 113b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::subtle::NoBarrier_Load(&g_native_tls_key); 114b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES) { 115b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat CHECK(PlatformThreadLocalStorage::AllocTLS(&key)); 116b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 117b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // The TLS_KEY_OUT_OF_INDEXES is used to find out whether the key is set or 118b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // not in NoBarrier_CompareAndSwap, but Posix doesn't have invalid key, we 119b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // define an almost impossible value be it. 120b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // If we really get TLS_KEY_OUT_OF_INDEXES as value of key, just alloc 121b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // another TLS slot. 122b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES) { 123b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::TLSKey tmp = key; 124b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat CHECK(PlatformThreadLocalStorage::AllocTLS(&key) && 125b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat key != PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES); 126b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::FreeTLS(tmp); 127b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 1283a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // Atomically test-and-set the tls_key. If the key is 1293a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // TLS_KEY_OUT_OF_INDEXES, go ahead and set it. Otherwise, do nothing, as 130b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // another thread already did our dirty work. 131b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES != 132cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko static_cast<PlatformThreadLocalStorage::TLSKey>( 133cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko base::subtle::NoBarrier_CompareAndSwap( 134cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko &g_native_tls_key, 135cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES, key))) { 136b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // We've been shortcut. Another thread replaced g_native_tls_key first so 137b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // we need to destroy our index and use the one the other thread got 138b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // first. 139b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::FreeTLS(key); 140b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat key = base::subtle::NoBarrier_Load(&g_native_tls_key); 141b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 142b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 143b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat CHECK(!PlatformThreadLocalStorage::GetTLSValue(key)); 144b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 1453a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // Some allocators, such as TCMalloc, make use of thread local storage. As a 1463a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // result, any attempt to call new (or malloc) will lazily cause such a system 1473a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // to initialize, which will include registering for a TLS key. If we are not 1483a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // careful here, then that request to create a key will call new back, and 1493a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // we'll have an infinite loop. We avoid that as follows: Use a stack 1503a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // allocated vector, so that we don't have dependence on our allocator until 1513a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // our service is in place. (i.e., don't even call new until after we're 1523a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // setup) 1533a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli TlsVectorEntry stack_allocated_tls_data[kThreadLocalStorageSize]; 154b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat memset(stack_allocated_tls_data, 0, sizeof(stack_allocated_tls_data)); 155b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Ensure that any rentrant calls change the temp version. 156b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::SetTLSValue(key, stack_allocated_tls_data); 157b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 158b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Allocate an array to store our data. 1593a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli TlsVectorEntry* tls_data = new TlsVectorEntry[kThreadLocalStorageSize]; 160b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat memcpy(tls_data, stack_allocated_tls_data, sizeof(stack_allocated_tls_data)); 161b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::SetTLSValue(key, tls_data); 162b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return tls_data; 163b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 164b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 1653a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civellivoid OnThreadExitInternal(TlsVectorEntry* tls_data) { 1663a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli DCHECK(tls_data); 1673a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // Some allocators, such as TCMalloc, use TLS. As a result, when a thread 168b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // terminates, one of the destructor calls we make may be to shut down an 1693a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // allocator. We have to be careful that after we've shutdown all of the known 1703a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // destructors (perchance including an allocator), that we don't call the 1713a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // allocator and cause it to resurrect itself (with no possibly destructor 1723a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // call to follow). We handle this problem as follows: Switch to using a stack 1733a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // allocated vector, so that we don't have dependence on our allocator after 1743a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // we have called all g_tls_metadata destructors. (i.e., don't even call 1753a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // delete[] after we're done with destructors.) 1763a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli TlsVectorEntry stack_allocated_tls_data[kThreadLocalStorageSize]; 177b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat memcpy(stack_allocated_tls_data, tls_data, sizeof(stack_allocated_tls_data)); 178b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Ensure that any re-entrant calls change the temp version. 179b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::TLSKey key = 180b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::subtle::NoBarrier_Load(&g_native_tls_key); 181b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::SetTLSValue(key, stack_allocated_tls_data); 182b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat delete[] tls_data; // Our last dependence on an allocator. 183b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 1843a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // Snapshot the TLS Metadata so we don't have to lock on every access. 1853a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli TlsMetadata tls_metadata[kThreadLocalStorageSize]; 1863a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli { 1873a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli base::AutoLock auto_lock(*GetTLSMetadataLock()); 1883a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli memcpy(tls_metadata, g_tls_metadata, sizeof(g_tls_metadata)); 1893a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli } 1903a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli 191b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat int remaining_attempts = kMaxDestructorIterations; 192b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat bool need_to_scan_destructors = true; 193b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat while (need_to_scan_destructors) { 194b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat need_to_scan_destructors = false; 195b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Try to destroy the first-created-slot (which is slot 1) in our last 1963a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // destructor call. That user was able to function, and define a slot with 197b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // no other services running, so perhaps it is a basic service (like an 1983a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // allocator) and should also be destroyed last. If we get the order wrong, 1993a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // then we'll iterate several more times, so it is really not that critical 2003a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // (but it might help). 2013a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli for (int slot = 0; slot < kThreadLocalStorageSize ; ++slot) { 2023a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli void* tls_value = stack_allocated_tls_data[slot].data; 2033a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli if (!tls_value || tls_metadata[slot].status == TlsStatus::FREE || 2043a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli stack_allocated_tls_data[slot].version != tls_metadata[slot].version) 205b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat continue; 206b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 207b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::ThreadLocalStorage::TLSDestructorFunc destructor = 2083a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli tls_metadata[slot].destructor; 2093a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli if (!destructor) 210b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat continue; 2113a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli stack_allocated_tls_data[slot].data = nullptr; // pre-clear the slot. 212b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat destructor(tls_value); 2133a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // Any destructor might have called a different service, which then set a 2143a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // different slot to a non-null value. Hence we need to check the whole 2153a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // vector again. This is a pthread standard. 216b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat need_to_scan_destructors = true; 217b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 218b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (--remaining_attempts <= 0) { 219b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat NOTREACHED(); // Destructors might not have been called. 220b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat break; 221b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 222b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 223b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 224b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Remove our stack allocated vector. 2253a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli PlatformThreadLocalStorage::SetTLSValue(key, nullptr); 226b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 227b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 228b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace 229b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 230b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace base { 231b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 232b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace internal { 233b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 234b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#if defined(OS_WIN) 235b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid PlatformThreadLocalStorage::OnThreadExit() { 236b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::TLSKey key = 237b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::subtle::NoBarrier_Load(&g_native_tls_key); 238b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES) 239b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return; 240b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void *tls_data = GetTLSValue(key); 241b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Maybe we have never initialized TLS for this thread. 242b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (!tls_data) 243b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return; 2443a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli OnThreadExitInternal(static_cast<TlsVectorEntry*>(tls_data)); 245b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 246b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#elif defined(OS_POSIX) 247b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid PlatformThreadLocalStorage::OnThreadExit(void* value) { 2483a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli OnThreadExitInternal(static_cast<TlsVectorEntry*>(value)); 249b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 250b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#endif // defined(OS_WIN) 251b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 252b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace internal 253b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 254b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ThreadLocalStorage::StaticSlot::Initialize(TLSDestructorFunc destructor) { 255b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::TLSKey key = 256b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::subtle::NoBarrier_Load(&g_native_tls_key); 257b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES || 2583a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli !PlatformThreadLocalStorage::GetTLSValue(key)) { 259b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat ConstructTlsVector(); 2603a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli } 261b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 262b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Grab a new slot. 2633a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli slot_ = kInvalidSlotValue; 2643a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli version_ = 0; 2653a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli { 2663a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli base::AutoLock auto_lock(*GetTLSMetadataLock()); 2673a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli for (int i = 0; i < kThreadLocalStorageSize; ++i) { 2683a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // Tracking the last assigned slot is an attempt to find the next 2693a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // available slot within one iteration. Under normal usage, slots remain 2703a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // in use for the lifetime of the process (otherwise before we reclaimed 2713a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // slots, we would have run out of slots). This makes it highly likely the 2723a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // next slot is going to be a free slot. 2733a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli size_t slot_candidate = 2743a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli (g_last_assigned_slot + 1 + i) % kThreadLocalStorageSize; 2753a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli if (g_tls_metadata[slot_candidate].status == TlsStatus::FREE) { 2763a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli g_tls_metadata[slot_candidate].status = TlsStatus::IN_USE; 2773a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli g_tls_metadata[slot_candidate].destructor = destructor; 2783a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli g_last_assigned_slot = slot_candidate; 2793a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli slot_ = slot_candidate; 2803a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli version_ = g_tls_metadata[slot_candidate].version; 2813a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli break; 2823a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli } 2833a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli } 2843a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli } 2853a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli CHECK_NE(slot_, kInvalidSlotValue); 286b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat CHECK_LT(slot_, kThreadLocalStorageSize); 287b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 288b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Setup our destructor. 289cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko base::subtle::Release_Store(&initialized_, 1); 290b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 291b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 292b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ThreadLocalStorage::StaticSlot::Free() { 2933a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli DCHECK_NE(slot_, kInvalidSlotValue); 294b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK_LT(slot_, kThreadLocalStorageSize); 2953a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli { 2963a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli base::AutoLock auto_lock(*GetTLSMetadataLock()); 2973a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli g_tls_metadata[slot_].status = TlsStatus::FREE; 2983a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli g_tls_metadata[slot_].destructor = nullptr; 2993a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli ++(g_tls_metadata[slot_].version); 3003a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli } 3013a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli slot_ = kInvalidSlotValue; 302cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko base::subtle::Release_Store(&initialized_, 0); 303b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 304b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 305b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid* ThreadLocalStorage::StaticSlot::Get() const { 3063a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli TlsVectorEntry* tls_data = static_cast<TlsVectorEntry*>( 307b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::GetTLSValue( 308b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::subtle::NoBarrier_Load(&g_native_tls_key))); 309b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (!tls_data) 310b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat tls_data = ConstructTlsVector(); 3113a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli DCHECK_NE(slot_, kInvalidSlotValue); 312b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK_LT(slot_, kThreadLocalStorageSize); 3133a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // Version mismatches means this slot was previously freed. 3143a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli if (tls_data[slot_].version != version_) 3153a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli return nullptr; 3163a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli return tls_data[slot_].data; 317b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 318b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 319b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ThreadLocalStorage::StaticSlot::Set(void* value) { 3203a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli TlsVectorEntry* tls_data = static_cast<TlsVectorEntry*>( 321b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::GetTLSValue( 322b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::subtle::NoBarrier_Load(&g_native_tls_key))); 323b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (!tls_data) 324b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat tls_data = ConstructTlsVector(); 3253a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli DCHECK_NE(slot_, kInvalidSlotValue); 326b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK_LT(slot_, kThreadLocalStorageSize); 3273a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli tls_data[slot_].data = value; 3283a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli tls_data[slot_].version = version_; 3293a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli} 3303a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli 3313a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay CivelliThreadLocalStorage::Slot::Slot(TLSDestructorFunc destructor) { 3323a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli tls_slot_.Initialize(destructor); 3333a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli} 3343a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli 3353a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay CivelliThreadLocalStorage::Slot::~Slot() { 3363a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli tls_slot_.Free(); 3373a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli} 3383a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli 3393a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civellivoid* ThreadLocalStorage::Slot::Get() const { 3403a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli return tls_slot_.Get(); 3413a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli} 3423a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli 3433a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civellivoid ThreadLocalStorage::Slot::Set(void* value) { 3443a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli tls_slot_.Set(value); 345b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 346b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 347b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace base 348