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