xref: /aosp_15_r20/external/cronet/base/threading/thread_local_storage.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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