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