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