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" 9cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#include "build/build_config.h" 10b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 11b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratusing base::internal::PlatformThreadLocalStorage; 12b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 13b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace { 14b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// In order to make TLS destructors work, we need to keep around a function 15b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// pointer to the destructor for each slot. We keep this array of pointers in a 16b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// global (static) array. 17b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// We use the single OS-level TLS slot (giving us one pointer per thread) to 18b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// hold a pointer to a per-thread array (table) of slots that we allocate to 19b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Chromium consumers. 20b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 21b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// g_native_tls_key is the one native TLS that we use. It stores our table. 22b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratbase::subtle::Atomic32 g_native_tls_key = 23b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES; 24b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 25b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// g_last_used_tls_key is the high-water-mark of allocated thread local storage. 26b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Each allocation is an index into our g_tls_destructors[]. Each such index is 27b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// assigned to the instance variable slot_ in a ThreadLocalStorage::Slot 28b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// instance. We reserve the value slot_ == 0 to indicate that the corresponding 29b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// instance of ThreadLocalStorage::Slot has been freed (i.e., destructor called, 30b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// etc.). This reserved use of 0 is then stated as the initial value of 31b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// g_last_used_tls_key, so that the first issued index will be 1. 32b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratbase::subtle::Atomic32 g_last_used_tls_key = 0; 33b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 34b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// The maximum number of 'slots' in our thread local storage stack. 35b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratconst int kThreadLocalStorageSize = 256; 36b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 37b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// The maximum number of times to try to clear slots by calling destructors. 38b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Use pthread naming convention for clarity. 39b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratconst int kMaxDestructorIterations = kThreadLocalStorageSize; 40b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 41b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// An array of destructor function pointers for the slots. If a slot has a 42b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// destructor, it will be stored in its corresponding entry in this array. 43b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// The elements are volatile to ensure that when the compiler reads the value 44b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// to potentially call the destructor, it does so once, and that value is tested 45b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// for null-ness and then used. Yes, that would be a weird de-optimization, 46b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// but I can imagine some register machines where it was just as easy to 47b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// re-fetch an array element, and I want to be sure a call to free the key 48b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// (i.e., null out the destructor entry) that happens on a separate thread can't 49b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// hurt the racy calls to the destructors on another thread. 50b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvolatile base::ThreadLocalStorage::TLSDestructorFunc 51b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat g_tls_destructors[kThreadLocalStorageSize]; 52b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 53b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// This function is called to initialize our entire Chromium TLS system. 54b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// It may be called very early, and we need to complete most all of the setup 55b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// (initialization) before calling *any* memory allocator functions, which may 56b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// recursively depend on this initialization. 57b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// As a result, we use Atomics, and avoid anything (like a singleton) that might 58b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// require memory allocations. 59b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid** ConstructTlsVector() { 60b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::TLSKey key = 61b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::subtle::NoBarrier_Load(&g_native_tls_key); 62b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES) { 63b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat CHECK(PlatformThreadLocalStorage::AllocTLS(&key)); 64b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 65b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // The TLS_KEY_OUT_OF_INDEXES is used to find out whether the key is set or 66b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // not in NoBarrier_CompareAndSwap, but Posix doesn't have invalid key, we 67b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // define an almost impossible value be it. 68b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // If we really get TLS_KEY_OUT_OF_INDEXES as value of key, just alloc 69b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // another TLS slot. 70b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES) { 71b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::TLSKey tmp = key; 72b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat CHECK(PlatformThreadLocalStorage::AllocTLS(&key) && 73b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat key != PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES); 74b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::FreeTLS(tmp); 75b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 76b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Atomically test-and-set the tls_key. If the key is 77b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // TLS_KEY_OUT_OF_INDEXES, go ahead and set it. Otherwise, do nothing, as 78b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // another thread already did our dirty work. 79b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES != 80cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko static_cast<PlatformThreadLocalStorage::TLSKey>( 81cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko base::subtle::NoBarrier_CompareAndSwap( 82cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko &g_native_tls_key, 83cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES, key))) { 84b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // We've been shortcut. Another thread replaced g_native_tls_key first so 85b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // we need to destroy our index and use the one the other thread got 86b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // first. 87b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::FreeTLS(key); 88b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat key = base::subtle::NoBarrier_Load(&g_native_tls_key); 89b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 90b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 91b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat CHECK(!PlatformThreadLocalStorage::GetTLSValue(key)); 92b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 93b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Some allocators, such as TCMalloc, make use of thread local storage. 94b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // As a result, any attempt to call new (or malloc) will lazily cause such a 95b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // system to initialize, which will include registering for a TLS key. If we 96b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // are not careful here, then that request to create a key will call new back, 97b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // and we'll have an infinite loop. We avoid that as follows: 98b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Use a stack allocated vector, so that we don't have dependence on our 99b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // allocator until our service is in place. (i.e., don't even call new until 100b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // after we're setup) 101b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void* stack_allocated_tls_data[kThreadLocalStorageSize]; 102b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat memset(stack_allocated_tls_data, 0, sizeof(stack_allocated_tls_data)); 103b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Ensure that any rentrant calls change the temp version. 104b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::SetTLSValue(key, stack_allocated_tls_data); 105b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 106b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Allocate an array to store our data. 107b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void** tls_data = new void*[kThreadLocalStorageSize]; 108b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat memcpy(tls_data, stack_allocated_tls_data, sizeof(stack_allocated_tls_data)); 109b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::SetTLSValue(key, tls_data); 110b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return tls_data; 111b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 112b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 113b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid OnThreadExitInternal(void* value) { 114b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK(value); 115b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void** tls_data = static_cast<void**>(value); 116b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Some allocators, such as TCMalloc, use TLS. As a result, when a thread 117b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // terminates, one of the destructor calls we make may be to shut down an 118b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // allocator. We have to be careful that after we've shutdown all of the 119b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // known destructors (perchance including an allocator), that we don't call 120b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // the allocator and cause it to resurrect itself (with no possibly destructor 121b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // call to follow). We handle this problem as follows: 122b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Switch to using a stack allocated vector, so that we don't have dependence 123b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // on our allocator after we have called all g_tls_destructors. (i.e., don't 124b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // even call delete[] after we're done with destructors.) 125b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void* stack_allocated_tls_data[kThreadLocalStorageSize]; 126b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat memcpy(stack_allocated_tls_data, tls_data, sizeof(stack_allocated_tls_data)); 127b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Ensure that any re-entrant calls change the temp version. 128b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::TLSKey key = 129b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::subtle::NoBarrier_Load(&g_native_tls_key); 130b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::SetTLSValue(key, stack_allocated_tls_data); 131b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat delete[] tls_data; // Our last dependence on an allocator. 132b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 133b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat int remaining_attempts = kMaxDestructorIterations; 134b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat bool need_to_scan_destructors = true; 135b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat while (need_to_scan_destructors) { 136b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat need_to_scan_destructors = false; 137b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Try to destroy the first-created-slot (which is slot 1) in our last 138b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // destructor call. That user was able to function, and define a slot with 139b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // no other services running, so perhaps it is a basic service (like an 140b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // allocator) and should also be destroyed last. If we get the order wrong, 141b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // then we'll itterate several more times, so it is really not that 142b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // critical (but it might help). 143b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::subtle::Atomic32 last_used_tls_key = 144b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::subtle::NoBarrier_Load(&g_last_used_tls_key); 145b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat for (int slot = last_used_tls_key; slot > 0; --slot) { 146b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void* tls_value = stack_allocated_tls_data[slot]; 147b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (tls_value == NULL) 148b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat continue; 149b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 150b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::ThreadLocalStorage::TLSDestructorFunc destructor = 151b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat g_tls_destructors[slot]; 152b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (destructor == NULL) 153b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat continue; 154b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat stack_allocated_tls_data[slot] = NULL; // pre-clear the slot. 155b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat destructor(tls_value); 156b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Any destructor might have called a different service, which then set 157b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // a different slot to a non-NULL value. Hence we need to check 158b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // the whole vector again. This is a pthread standard. 159b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat need_to_scan_destructors = true; 160b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 161b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (--remaining_attempts <= 0) { 162b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat NOTREACHED(); // Destructors might not have been called. 163b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat break; 164b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 165b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 166b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 167b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Remove our stack allocated vector. 168b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::SetTLSValue(key, NULL); 169b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 170b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 171b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace 172b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 173b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace base { 174b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 175b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace internal { 176b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 177b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#if defined(OS_WIN) 178b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid PlatformThreadLocalStorage::OnThreadExit() { 179b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::TLSKey key = 180b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::subtle::NoBarrier_Load(&g_native_tls_key); 181b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES) 182b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return; 183b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void *tls_data = GetTLSValue(key); 184b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Maybe we have never initialized TLS for this thread. 185b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (!tls_data) 186b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return; 187b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat OnThreadExitInternal(tls_data); 188b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 189b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#elif defined(OS_POSIX) 190b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid PlatformThreadLocalStorage::OnThreadExit(void* value) { 191b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat OnThreadExitInternal(value); 192b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 193b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#endif // defined(OS_WIN) 194b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 195b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace internal 196b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 197b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratThreadLocalStorage::Slot::Slot(TLSDestructorFunc destructor) { 198b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat slot_ = 0; 199cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko base::subtle::Release_Store(&initialized_, 0); 200b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat Initialize(destructor); 201b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 202b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 203b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ThreadLocalStorage::StaticSlot::Initialize(TLSDestructorFunc destructor) { 204b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::TLSKey key = 205b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::subtle::NoBarrier_Load(&g_native_tls_key); 206b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES || 207b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat !PlatformThreadLocalStorage::GetTLSValue(key)) 208b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat ConstructTlsVector(); 209b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 210b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Grab a new slot. 211b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat slot_ = base::subtle::NoBarrier_AtomicIncrement(&g_last_used_tls_key, 1); 212b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK_GT(slot_, 0); 213b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat CHECK_LT(slot_, kThreadLocalStorageSize); 214b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 215b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Setup our destructor. 216b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat g_tls_destructors[slot_] = destructor; 217cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko base::subtle::Release_Store(&initialized_, 1); 218b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 219b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 220b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ThreadLocalStorage::StaticSlot::Free() { 221b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // At this time, we don't reclaim old indices for TLS slots. 222b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // So all we need to do is wipe the destructor. 223b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK_GT(slot_, 0); 224b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK_LT(slot_, kThreadLocalStorageSize); 225b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat g_tls_destructors[slot_] = NULL; 226b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat slot_ = 0; 227cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko base::subtle::Release_Store(&initialized_, 0); 228b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 229b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 230b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid* ThreadLocalStorage::StaticSlot::Get() const { 231b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void** tls_data = static_cast<void**>( 232b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::GetTLSValue( 233b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::subtle::NoBarrier_Load(&g_native_tls_key))); 234b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (!tls_data) 235b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat tls_data = ConstructTlsVector(); 236b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK_GT(slot_, 0); 237b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK_LT(slot_, kThreadLocalStorageSize); 238b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return tls_data[slot_]; 239b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 240b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 241b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ThreadLocalStorage::StaticSlot::Set(void* value) { 242b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void** tls_data = static_cast<void**>( 243b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThreadLocalStorage::GetTLSValue( 244b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::subtle::NoBarrier_Load(&g_native_tls_key))); 245b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (!tls_data) 246b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat tls_data = ConstructTlsVector(); 247b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK_GT(slot_, 0); 248b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK_LT(slot_, kThreadLocalStorageSize); 249b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat tls_data[slot_] = value; 250b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 251b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 252b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace base 253