1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_THREADING_THREAD_LOCAL_STORAGE_H_
6 #define BASE_THREADING_THREAD_LOCAL_STORAGE_H_
7 
8 #include <stdint.h>
9 
10 #include "base/atomicops.h"
11 #include "base/base_export.h"
12 #include "base/macros.h"
13 #include "build/build_config.h"
14 
15 #if defined(OS_WIN)
16 #include "base/win/windows_types.h"
17 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
18 #include <pthread.h>
19 #endif
20 
21 namespace heap_profiling {
22 class ScopedAllowAlloc;
23 }  // namespace heap_profiling
24 
25 namespace ui {
26 class TLSDestructionCheckerForX11;
27 }
28 
29 namespace base {
30 
31 class SamplingHeapProfiler;
32 
33 namespace debug {
34 class GlobalActivityTracker;
35 }  // namespace debug
36 
37 namespace trace_event {
38 class MallocDumpProvider;
39 }  // namespace trace_event
40 
41 namespace internal {
42 
43 class ThreadLocalStorageTestInternal;
44 
45 // WARNING: You should *NOT* use this class directly.
46 // PlatformThreadLocalStorage is a low-level abstraction of the OS's TLS
47 // interface. Instead, you should use one of the following:
48 // * ThreadLocalBoolean (from thread_local.h) for booleans.
49 // * ThreadLocalPointer (from thread_local.h) for pointers.
50 // * ThreadLocalStorage::StaticSlot/Slot for more direct control of the slot.
51 class BASE_EXPORT PlatformThreadLocalStorage {
52  public:
53 
54 #if defined(OS_WIN)
55   typedef unsigned long TLSKey;
56   enum : unsigned { TLS_KEY_OUT_OF_INDEXES = TLS_OUT_OF_INDEXES };
57 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
58   typedef pthread_key_t TLSKey;
59   // The following is a "reserved key" which is used in our generic Chromium
60   // ThreadLocalStorage implementation.  We expect that an OS will not return
61   // such a key, but if it is returned (i.e., the OS tries to allocate it) we
62   // will just request another key.
63   enum { TLS_KEY_OUT_OF_INDEXES = 0x7FFFFFFF };
64 #endif
65 
66   // The following methods need to be supported on each OS platform, so that
67   // the Chromium ThreadLocalStore functionality can be constructed.
68   // Chromium will use these methods to acquire a single OS slot, and then use
69   // that to support a much larger number of Chromium slots (independent of the
70   // OS restrictions).
71   // The following returns true if it successfully is able to return an OS
72   // key in |key|.
73   static bool AllocTLS(TLSKey* key);
74   // Note: FreeTLS() doesn't have to be called, it is fine with this leak, OS
75   // might not reuse released slot, you might just reset the TLS value with
76   // SetTLSValue().
77   static void FreeTLS(TLSKey key);
78   static void SetTLSValue(TLSKey key, void* value);
GetTLSValue(TLSKey key)79   static void* GetTLSValue(TLSKey key) {
80 #if defined(OS_WIN)
81     return TlsGetValue(key);
82 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
83     return pthread_getspecific(key);
84 #endif
85   }
86 
87   // Each platform (OS implementation) is required to call this method on each
88   // terminating thread when the thread is about to terminate.  This method
89   // will then call all registered destructors for slots in Chromium
90   // ThreadLocalStorage, until there are no slot values remaining as having
91   // been set on this thread.
92   // Destructors may end up being called multiple times on a terminating
93   // thread, as other destructors may re-set slots that were previously
94   // destroyed.
95 #if defined(OS_WIN)
96   // Since Windows which doesn't support TLS destructor, the implementation
97   // should use GetTLSValue() to retrieve the value of TLS slot.
98   static void OnThreadExit();
99 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
100   // |Value| is the data stored in TLS slot, The implementation can't use
101   // GetTLSValue() to retrieve the value of slot as it has already been reset
102   // in Posix.
103   static void OnThreadExit(void* value);
104   // Normally, Chrome runs as a process, so freeing the TLS is not needed since
105   // the OS will perform that while it's reclaiming the process' memory upon
106   // termination. If, however, this code is used inside a library that is
107   // dynamically loaded and unloaded, the consumer is responsible for calling
108   // this after all Chrome threads have stopped and prior to unloading the
109   // library.
110   static void ForceFreeTLS();
111 #endif
112 };
113 
114 }  // namespace internal
115 
116 // Wrapper for thread local storage.  This class doesn't do much except provide
117 // an API for portability.
118 class BASE_EXPORT ThreadLocalStorage {
119  public:
120   // Prototype for the TLS destructor function, which can be optionally used to
121   // cleanup thread local storage on thread exit.  'value' is the data that is
122   // stored in thread local storage.
123   typedef void (*TLSDestructorFunc)(void* value);
124 
125   // A key representing one value stored in TLS. Use as a class member or a
126   // local variable. If you need a static storage duration variable, use the
127   // following pattern with a NoDestructor<Slot>:
128   // void MyDestructorFunc(void* value);
129   // ThreadLocalStorage::Slot& ImportantContentTLS() {
130   //   static NoDestructor<ThreadLocalStorage::Slot> important_content_tls(
131   //       &MyDestructorFunc);
132   //   return *important_content_tls;
133   // }
134   class BASE_EXPORT Slot final {
135    public:
136     // |destructor| is a pointer to a function to perform per-thread cleanup of
137     // this object.  If set to nullptr, no cleanup is done for this TLS slot.
138     explicit Slot(TLSDestructorFunc destructor = nullptr);
139     // If a destructor was set for this slot, removes the destructor so that
140     // remaining threads exiting will not free data.
141     ~Slot();
142 
143     // Get the thread-local value stored in slot 'slot'.
144     // Values are guaranteed to initially be zero.
145     void* Get() const;
146 
147     // Set the thread-local value stored in slot 'slot' to
148     // value 'value'.
149     void Set(void* value);
150 
151    private:
152     void Initialize(TLSDestructorFunc destructor);
153     void Free();
154 
155     static constexpr int kInvalidSlotValue = -1;
156     int slot_ = kInvalidSlotValue;
157     uint32_t version_ = 0;
158 
159     DISALLOW_COPY_AND_ASSIGN(Slot);
160   };
161 
162  private:
163   // In most cases, most callers should not need access to HasBeenDestroyed().
164   // If you are working in code that runs during thread destruction, contact the
165   // base OWNERs for advice and then make a friend request.
166   //
167   // Returns |true| if Chrome's implementation of TLS has been destroyed during
168   // thread destruction. Attempting to call Slot::Get() during destruction is
169   // disallowed and will hit a DCHECK. Any code that relies on TLS during thread
170   // destruction must first check this method before calling Slot::Get().
171   friend class base::SamplingHeapProfiler;
172   friend class base::internal::ThreadLocalStorageTestInternal;
173   friend class base::trace_event::MallocDumpProvider;
174   friend class debug::GlobalActivityTracker;
175   friend class heap_profiling::ScopedAllowAlloc;
176   friend class ui::TLSDestructionCheckerForX11;
177   static bool HasBeenDestroyed();
178 
179   DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorage);
180 };
181 
182 }  // namespace base
183 
184 #endif  // BASE_THREADING_THREAD_LOCAL_STORAGE_H_
185