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