xref: /aosp_15_r20/external/cronet/base/allocator/dispatcher/tls.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2022 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_ALLOCATOR_DISPATCHER_TLS_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_ALLOCATOR_DISPATCHER_TLS_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <string_view>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
11*6777b538SAndroid Build Coastguard Worker 
12*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_POSIX)  // the current allocation mechanism (mmap) and TLS
13*6777b538SAndroid Build Coastguard Worker                          // support (pthread) are both defined by POSIX
14*6777b538SAndroid Build Coastguard Worker #define USE_LOCAL_TLS_EMULATION() true
15*6777b538SAndroid Build Coastguard Worker #else
16*6777b538SAndroid Build Coastguard Worker #define USE_LOCAL_TLS_EMULATION() false
17*6777b538SAndroid Build Coastguard Worker #endif
18*6777b538SAndroid Build Coastguard Worker 
19*6777b538SAndroid Build Coastguard Worker #if USE_LOCAL_TLS_EMULATION()
20*6777b538SAndroid Build Coastguard Worker #include <algorithm>
21*6777b538SAndroid Build Coastguard Worker #include <atomic>
22*6777b538SAndroid Build Coastguard Worker #include <memory>
23*6777b538SAndroid Build Coastguard Worker #include <mutex>
24*6777b538SAndroid Build Coastguard Worker 
25*6777b538SAndroid Build Coastguard Worker #include "base/base_export.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/compiler_specific.h"
28*6777b538SAndroid Build Coastguard Worker #include "partition_alloc/partition_alloc_constants.h"
29*6777b538SAndroid Build Coastguard Worker 
30*6777b538SAndroid Build Coastguard Worker #include <pthread.h>
31*6777b538SAndroid Build Coastguard Worker 
32*6777b538SAndroid Build Coastguard Worker #if HAS_FEATURE(thread_sanitizer)
33*6777b538SAndroid Build Coastguard Worker #define DISABLE_TSAN_INSTRUMENTATION __attribute__((no_sanitize("thread")))
34*6777b538SAndroid Build Coastguard Worker #else
35*6777b538SAndroid Build Coastguard Worker #define DISABLE_TSAN_INSTRUMENTATION
36*6777b538SAndroid Build Coastguard Worker #endif
37*6777b538SAndroid Build Coastguard Worker 
38*6777b538SAndroid Build Coastguard Worker #define STR_HELPER(x) #x
39*6777b538SAndroid Build Coastguard Worker #define STR(x) STR_HELPER(x)
40*6777b538SAndroid Build Coastguard Worker 
41*6777b538SAndroid Build Coastguard Worker // Verify that a condition holds and cancel the process in case it doesn't. The
42*6777b538SAndroid Build Coastguard Worker // functionality is similar to RAW_CHECK but includes more information in the
43*6777b538SAndroid Build Coastguard Worker // logged messages. It is non allocating to prevent recursions.
44*6777b538SAndroid Build Coastguard Worker #define TLS_RAW_CHECK(error_message, condition) \
45*6777b538SAndroid Build Coastguard Worker   TLS_RAW_CHECK_IMPL(error_message, condition, __FILE__, __LINE__)
46*6777b538SAndroid Build Coastguard Worker 
47*6777b538SAndroid Build Coastguard Worker #define TLS_RAW_CHECK_IMPL(error_message, condition, file, line)        \
48*6777b538SAndroid Build Coastguard Worker   do {                                                                  \
49*6777b538SAndroid Build Coastguard Worker     if (!(condition)) {                                                 \
50*6777b538SAndroid Build Coastguard Worker       constexpr const char* message =                                   \
51*6777b538SAndroid Build Coastguard Worker           "TLS System: " error_message " Failed condition '" #condition \
52*6777b538SAndroid Build Coastguard Worker           "' in (" file "@" STR(line) ").\n";                           \
53*6777b538SAndroid Build Coastguard Worker       ::logging::RawCheckFailure(message);                              \
54*6777b538SAndroid Build Coastguard Worker     }                                                                   \
55*6777b538SAndroid Build Coastguard Worker   } while (0)
56*6777b538SAndroid Build Coastguard Worker 
57*6777b538SAndroid Build Coastguard Worker namespace base::debug {
58*6777b538SAndroid Build Coastguard Worker struct CrashKeyString;
59*6777b538SAndroid Build Coastguard Worker }
60*6777b538SAndroid Build Coastguard Worker 
61*6777b538SAndroid Build Coastguard Worker namespace base::allocator::dispatcher {
62*6777b538SAndroid Build Coastguard Worker namespace internal {
63*6777b538SAndroid Build Coastguard Worker 
64*6777b538SAndroid Build Coastguard Worker // Allocate memory using POSIX' mmap and unmap functionality. The allocator
65*6777b538SAndroid Build Coastguard Worker // implements the allocator interface required by ThreadLocalStorage.
66*6777b538SAndroid Build Coastguard Worker struct BASE_EXPORT MMapAllocator {
67*6777b538SAndroid Build Coastguard Worker // The minimum size of a memory chunk when allocating. Even for chunks with
68*6777b538SAndroid Build Coastguard Worker // fewer bytes, at least AllocationChunkSize bytes are allocated. For mmap, this
69*6777b538SAndroid Build Coastguard Worker // is usually the page size of the system.
70*6777b538SAndroid Build Coastguard Worker // For various OS-CPU combinations, partition_alloc::PartitionPageSize() is not
71*6777b538SAndroid Build Coastguard Worker // constexpr. Hence, we can not use this value but define it locally.
72*6777b538SAndroid Build Coastguard Worker #if defined(PAGE_ALLOCATOR_CONSTANTS_ARE_CONSTEXPR) && \
73*6777b538SAndroid Build Coastguard Worker     PAGE_ALLOCATOR_CONSTANTS_ARE_CONSTEXPR
74*6777b538SAndroid Build Coastguard Worker   constexpr static size_t AllocationChunkSize =
75*6777b538SAndroid Build Coastguard Worker       partition_alloc::PartitionPageSize();
76*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_APPLE)
77*6777b538SAndroid Build Coastguard Worker   constexpr static size_t AllocationChunkSize = 16384;
78*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_64_BITS)
79*6777b538SAndroid Build Coastguard Worker   constexpr static size_t AllocationChunkSize = 16384;
80*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64)
81*6777b538SAndroid Build Coastguard Worker   constexpr static size_t AllocationChunkSize = 16384;
82*6777b538SAndroid Build Coastguard Worker #else
83*6777b538SAndroid Build Coastguard Worker   constexpr static size_t AllocationChunkSize = 4096;
84*6777b538SAndroid Build Coastguard Worker #endif
85*6777b538SAndroid Build Coastguard Worker 
86*6777b538SAndroid Build Coastguard Worker   // Allocate size_in_bytes bytes of raw memory. Return nullptr if allocation
87*6777b538SAndroid Build Coastguard Worker   // fails.
88*6777b538SAndroid Build Coastguard Worker   void* AllocateMemory(size_t size_in_bytes);
89*6777b538SAndroid Build Coastguard Worker   // Free the raw memory pointed to by pointer_to_allocated. Returns a boolean
90*6777b538SAndroid Build Coastguard Worker   // value indicating if the free was successful.
91*6777b538SAndroid Build Coastguard Worker   bool FreeMemoryForTesting(void* pointer_to_allocated, size_t size_in_bytes);
92*6777b538SAndroid Build Coastguard Worker };
93*6777b538SAndroid Build Coastguard Worker 
94*6777b538SAndroid Build Coastguard Worker // The allocator used by default for the thread local storage.
95*6777b538SAndroid Build Coastguard Worker using DefaultAllocator = MMapAllocator;
96*6777b538SAndroid Build Coastguard Worker 
97*6777b538SAndroid Build Coastguard Worker using OnThreadTerminationFunction = void (*)(void*);
98*6777b538SAndroid Build Coastguard Worker 
99*6777b538SAndroid Build Coastguard Worker // The TLS system used by default for the thread local storage. It stores and
100*6777b538SAndroid Build Coastguard Worker // retrieves thread specific data pointers.
101*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT PThreadTLSSystem {
102*6777b538SAndroid Build Coastguard Worker  public:
103*6777b538SAndroid Build Coastguard Worker   PThreadTLSSystem();
104*6777b538SAndroid Build Coastguard Worker 
105*6777b538SAndroid Build Coastguard Worker   PThreadTLSSystem(const PThreadTLSSystem&) = delete;
106*6777b538SAndroid Build Coastguard Worker   PThreadTLSSystem(PThreadTLSSystem&&);
107*6777b538SAndroid Build Coastguard Worker   PThreadTLSSystem& operator=(const PThreadTLSSystem&) = delete;
108*6777b538SAndroid Build Coastguard Worker   PThreadTLSSystem& operator=(PThreadTLSSystem&&);
109*6777b538SAndroid Build Coastguard Worker 
110*6777b538SAndroid Build Coastguard Worker   // Initialize the TLS system to store a data set for different threads.
111*6777b538SAndroid Build Coastguard Worker   // @param thread_termination_function An optional function which will be
112*6777b538SAndroid Build Coastguard Worker   // invoked upon termination of a thread.
113*6777b538SAndroid Build Coastguard Worker   bool Setup(OnThreadTerminationFunction thread_termination_function,
114*6777b538SAndroid Build Coastguard Worker              const std::string_view instance_id);
115*6777b538SAndroid Build Coastguard Worker   // Tear down the TLS system. After completing tear down, the thread
116*6777b538SAndroid Build Coastguard Worker   // termination function passed to Setup will not be invoked anymore.
117*6777b538SAndroid Build Coastguard Worker   bool TearDownForTesting();
118*6777b538SAndroid Build Coastguard Worker 
119*6777b538SAndroid Build Coastguard Worker   // Get the pointer to the data associated to the current thread. Returns
120*6777b538SAndroid Build Coastguard Worker   // nullptr if the TLS system is not initialized or no data was set before.
121*6777b538SAndroid Build Coastguard Worker   void* GetThreadSpecificData();
122*6777b538SAndroid Build Coastguard Worker   // Set the pointer to the data associated to the current thread. Return true
123*6777b538SAndroid Build Coastguard Worker   // if stored successfully, false otherwise.
124*6777b538SAndroid Build Coastguard Worker   bool SetThreadSpecificData(void* data);
125*6777b538SAndroid Build Coastguard Worker 
126*6777b538SAndroid Build Coastguard Worker  private:
127*6777b538SAndroid Build Coastguard Worker   base::debug::CrashKeyString* crash_key_ = nullptr;
128*6777b538SAndroid Build Coastguard Worker   pthread_key_t data_access_key_ = 0;
129*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
130*6777b538SAndroid Build Coastguard Worker   // From POSIX standard at https://www.open-std.org/jtc1/sc22/open/n4217.pdf:
131*6777b538SAndroid Build Coastguard Worker   // The effect of calling pthread_getspecific() or pthread_setspecific() with a
132*6777b538SAndroid Build Coastguard Worker   // key value not obtained from pthread_key_create() or after key has been
133*6777b538SAndroid Build Coastguard Worker   // deleted with pthread_key_delete() is undefined.
134*6777b538SAndroid Build Coastguard Worker   //
135*6777b538SAndroid Build Coastguard Worker   // Unfortunately, POSIX doesn't define a special value of pthread_key_t
136*6777b538SAndroid Build Coastguard Worker   // indicating an invalid key which would allow us to detect accesses outside
137*6777b538SAndroid Build Coastguard Worker   // of initialized state. Hence, to prevent us from drifting into the evil
138*6777b538SAndroid Build Coastguard Worker   // realm of undefined behaviour we store whether we're somewhere between Setup
139*6777b538SAndroid Build Coastguard Worker   // and Teardown.
140*6777b538SAndroid Build Coastguard Worker   std::atomic_bool initialized_{false};
141*6777b538SAndroid Build Coastguard Worker #endif
142*6777b538SAndroid Build Coastguard Worker };
143*6777b538SAndroid Build Coastguard Worker 
144*6777b538SAndroid Build Coastguard Worker using DefaultTLSSystem = PThreadTLSSystem;
145*6777b538SAndroid Build Coastguard Worker 
146*6777b538SAndroid Build Coastguard Worker // In some scenarios, most notably when testing, the allocator and TLS system
147*6777b538SAndroid Build Coastguard Worker // passed to |ThreadLocalStorage| are not copyable and have to be wrapped, i.e.
148*6777b538SAndroid Build Coastguard Worker // using std::reference_wrapper. |dereference| is a small helper to retrieve the
149*6777b538SAndroid Build Coastguard Worker // underlying value.
150*6777b538SAndroid Build Coastguard Worker template <typename T>
dereference(T & ref)151*6777b538SAndroid Build Coastguard Worker T& dereference(T& ref) {
152*6777b538SAndroid Build Coastguard Worker   return ref;
153*6777b538SAndroid Build Coastguard Worker }
154*6777b538SAndroid Build Coastguard Worker 
155*6777b538SAndroid Build Coastguard Worker template <typename T>
dereference(std::reference_wrapper<T> & ref)156*6777b538SAndroid Build Coastguard Worker T& dereference(std::reference_wrapper<T>& ref) {
157*6777b538SAndroid Build Coastguard Worker   // std::reference_wrapper requires a valid reference for construction,
158*6777b538SAndroid Build Coastguard Worker   // therefore, no need in checking here.
159*6777b538SAndroid Build Coastguard Worker   return ref.get();
160*6777b538SAndroid Build Coastguard Worker }
161*6777b538SAndroid Build Coastguard Worker 
162*6777b538SAndroid Build Coastguard Worker // Store thread local data. The data is organized in chunks, where each chunk
163*6777b538SAndroid Build Coastguard Worker // holds |ItemsPerChunk|. Each item may be free or used.
164*6777b538SAndroid Build Coastguard Worker //
165*6777b538SAndroid Build Coastguard Worker // When a thread requests data, the chunks are searched for a free data item,
166*6777b538SAndroid Build Coastguard Worker // which is registered for this thread and marked as |used|. Further requests by
167*6777b538SAndroid Build Coastguard Worker // this thread will then always return the same item. When a thread terminates,
168*6777b538SAndroid Build Coastguard Worker // the item will be reset and return to the pool of free items.
169*6777b538SAndroid Build Coastguard Worker //
170*6777b538SAndroid Build Coastguard Worker // Upon construction, the first chunk is created. If a thread requests data and
171*6777b538SAndroid Build Coastguard Worker // there is no free item available, another chunk is created. Upon destruction,
172*6777b538SAndroid Build Coastguard Worker // all memory is freed. Pointers to data items become invalid!
173*6777b538SAndroid Build Coastguard Worker //
174*6777b538SAndroid Build Coastguard Worker // Constructor and destructor are not thread safe.
175*6777b538SAndroid Build Coastguard Worker //
176*6777b538SAndroid Build Coastguard Worker // @tparam PayloadType The item type to be stored.
177*6777b538SAndroid Build Coastguard Worker // @tparam AllocatorType The allocator being used. An allocator must provide
178*6777b538SAndroid Build Coastguard Worker // the following interface:
179*6777b538SAndroid Build Coastguard Worker //  void* AllocateMemory(size_t size_in_bytes); // Allocate size_in_bytes bytes
180*6777b538SAndroid Build Coastguard Worker //  of raw memory.
181*6777b538SAndroid Build Coastguard Worker //  void FreeMemory(void* pointer_to_allocated, size_t size_in_bytes); // Free
182*6777b538SAndroid Build Coastguard Worker //  the raw memory pointed to by pointer_to_allocated.
183*6777b538SAndroid Build Coastguard Worker // Any failure in allocation or free must terminate the process.
184*6777b538SAndroid Build Coastguard Worker // @tparam TLSSystemType The TLS system being used. A TLS system must provide
185*6777b538SAndroid Build Coastguard Worker // the following interface:
186*6777b538SAndroid Build Coastguard Worker //  bool Setup(OnThreadTerminationFunction thread_termination_function);
187*6777b538SAndroid Build Coastguard Worker //  bool Destroy();
188*6777b538SAndroid Build Coastguard Worker //  void* GetThreadSpecificData();
189*6777b538SAndroid Build Coastguard Worker //  bool SetThreadSpecificData(void* data);
190*6777b538SAndroid Build Coastguard Worker // @tparam AllocationChunkSize The minimum size of a memory chunk that the
191*6777b538SAndroid Build Coastguard Worker // allocator can handle. We try to size the chunks so that each chunk uses this
192*6777b538SAndroid Build Coastguard Worker // size to the maximum.
193*6777b538SAndroid Build Coastguard Worker // @tparam IsDestructibleForTesting For testing purposes we allow the destructor
194*6777b538SAndroid Build Coastguard Worker // to perform clean up upon destruction. Otherwise, using the destructor will
195*6777b538SAndroid Build Coastguard Worker // result in a compilation failure.
196*6777b538SAndroid Build Coastguard Worker template <typename PayloadType,
197*6777b538SAndroid Build Coastguard Worker           typename AllocatorType,
198*6777b538SAndroid Build Coastguard Worker           typename TLSSystemType,
199*6777b538SAndroid Build Coastguard Worker           size_t AllocationChunkSize,
200*6777b538SAndroid Build Coastguard Worker           bool IsDestructibleForTesting>
201*6777b538SAndroid Build Coastguard Worker struct ThreadLocalStorage {
ThreadLocalStorageThreadLocalStorage202*6777b538SAndroid Build Coastguard Worker   explicit ThreadLocalStorage(const std::string_view instance_id)
203*6777b538SAndroid Build Coastguard Worker       : root_(AllocateAndInitializeChunk()) {
204*6777b538SAndroid Build Coastguard Worker     Initialize(instance_id);
205*6777b538SAndroid Build Coastguard Worker   }
206*6777b538SAndroid Build Coastguard Worker 
207*6777b538SAndroid Build Coastguard Worker   // Create a new instance of |ThreadLocalStorage| using the passed allocator
208*6777b538SAndroid Build Coastguard Worker   // and TLS system. This initializes the underlying TLS system and creates the
209*6777b538SAndroid Build Coastguard Worker   // first chunk of data.
ThreadLocalStorageThreadLocalStorage210*6777b538SAndroid Build Coastguard Worker   ThreadLocalStorage(const std::string_view instance_id,
211*6777b538SAndroid Build Coastguard Worker                      AllocatorType allocator,
212*6777b538SAndroid Build Coastguard Worker                      TLSSystemType tls_system)
213*6777b538SAndroid Build Coastguard Worker       : allocator_(std::move(allocator)),
214*6777b538SAndroid Build Coastguard Worker         tls_system_(std::move(tls_system)),
215*6777b538SAndroid Build Coastguard Worker         root_(AllocateAndInitializeChunk()) {
216*6777b538SAndroid Build Coastguard Worker     Initialize(instance_id);
217*6777b538SAndroid Build Coastguard Worker   }
218*6777b538SAndroid Build Coastguard Worker 
219*6777b538SAndroid Build Coastguard Worker   // Deletes an instance of |ThreadLocalStorage| and delete all the data chunks
220*6777b538SAndroid Build Coastguard Worker   // created.
~ThreadLocalStorageThreadLocalStorage221*6777b538SAndroid Build Coastguard Worker   ~ThreadLocalStorage() {
222*6777b538SAndroid Build Coastguard Worker     if constexpr (IsDestructibleForTesting) {
223*6777b538SAndroid Build Coastguard Worker       TearDownForTesting();
224*6777b538SAndroid Build Coastguard Worker     } else if constexpr (!IsDestructibleForTesting) {
225*6777b538SAndroid Build Coastguard Worker       static_assert(
226*6777b538SAndroid Build Coastguard Worker           IsDestructibleForTesting,
227*6777b538SAndroid Build Coastguard Worker           "ThreadLocalStorage cannot be destructed outside of test code.");
228*6777b538SAndroid Build Coastguard Worker     }
229*6777b538SAndroid Build Coastguard Worker   }
230*6777b538SAndroid Build Coastguard Worker 
231*6777b538SAndroid Build Coastguard Worker   // Explicitly prevent all forms of Copy/Move construction/assignment. For an
232*6777b538SAndroid Build Coastguard Worker   // exact copy of ThreadLocalStorage we would need to copy the mapping of
233*6777b538SAndroid Build Coastguard Worker   // thread to item, which we can't do at the moment. On the other side, our
234*6777b538SAndroid Build Coastguard Worker   // atomic members do not support moving out of the box.
235*6777b538SAndroid Build Coastguard Worker   ThreadLocalStorage(const ThreadLocalStorage&) = delete;
236*6777b538SAndroid Build Coastguard Worker   ThreadLocalStorage(ThreadLocalStorage&& other) = delete;
237*6777b538SAndroid Build Coastguard Worker   ThreadLocalStorage& operator=(const ThreadLocalStorage&) = delete;
238*6777b538SAndroid Build Coastguard Worker   ThreadLocalStorage& operator=(ThreadLocalStorage&&) = delete;
239*6777b538SAndroid Build Coastguard Worker 
240*6777b538SAndroid Build Coastguard Worker   // Get the data item for the current thread. If no data is registered so far,
241*6777b538SAndroid Build Coastguard Worker   // find a free item in the chunks and register it for the current thread.
GetThreadLocalDataThreadLocalStorage242*6777b538SAndroid Build Coastguard Worker   PayloadType* GetThreadLocalData() {
243*6777b538SAndroid Build Coastguard Worker     auto& tls_system = dereference(tls_system_);
244*6777b538SAndroid Build Coastguard Worker 
245*6777b538SAndroid Build Coastguard Worker     auto* slot = static_cast<SingleSlot*>(tls_system.GetThreadSpecificData());
246*6777b538SAndroid Build Coastguard Worker 
247*6777b538SAndroid Build Coastguard Worker     if (UNLIKELY(slot == nullptr)) {
248*6777b538SAndroid Build Coastguard Worker       slot = FindAndAllocateFreeSlot(root_.load(std::memory_order_relaxed));
249*6777b538SAndroid Build Coastguard Worker 
250*6777b538SAndroid Build Coastguard Worker       // We might be called in the course of handling a memory allocation. We do
251*6777b538SAndroid Build Coastguard Worker       // not use CHECK since they might allocate and cause a recursion.
252*6777b538SAndroid Build Coastguard Worker       TLS_RAW_CHECK("Failed to set thread specific data.",
253*6777b538SAndroid Build Coastguard Worker                     tls_system.SetThreadSpecificData(slot));
254*6777b538SAndroid Build Coastguard Worker 
255*6777b538SAndroid Build Coastguard Worker       // Reset the content to wipe out any previous data.
256*6777b538SAndroid Build Coastguard Worker       Reset(slot->item);
257*6777b538SAndroid Build Coastguard Worker     }
258*6777b538SAndroid Build Coastguard Worker 
259*6777b538SAndroid Build Coastguard Worker     return &(slot->item);
260*6777b538SAndroid Build Coastguard Worker   }
261*6777b538SAndroid Build Coastguard Worker 
262*6777b538SAndroid Build Coastguard Worker  private:
263*6777b538SAndroid Build Coastguard Worker   // Encapsulate the payload item and some administrative data.
264*6777b538SAndroid Build Coastguard Worker   struct SingleSlot {
265*6777b538SAndroid Build Coastguard Worker     PayloadType item;
266*6777b538SAndroid Build Coastguard Worker #if !defined(__cpp_lib_atomic_value_initialization) || \
267*6777b538SAndroid Build Coastguard Worker     __cpp_lib_atomic_value_initialization < 201911L
268*6777b538SAndroid Build Coastguard Worker     std::atomic_flag is_used = ATOMIC_FLAG_INIT;
269*6777b538SAndroid Build Coastguard Worker #else
270*6777b538SAndroid Build Coastguard Worker     std::atomic_flag is_used;
271*6777b538SAndroid Build Coastguard Worker #endif
272*6777b538SAndroid Build Coastguard Worker   };
273*6777b538SAndroid Build Coastguard Worker 
274*6777b538SAndroid Build Coastguard Worker   template <size_t NumberOfItems>
275*6777b538SAndroid Build Coastguard Worker   struct ChunkT {
276*6777b538SAndroid Build Coastguard Worker     SingleSlot slots[NumberOfItems];
277*6777b538SAndroid Build Coastguard Worker     // Pointer to the next chunk.
278*6777b538SAndroid Build Coastguard Worker     std::atomic<ChunkT*> next_chunk = nullptr;
279*6777b538SAndroid Build Coastguard Worker     // Helper flag to ensure we create the next chunk only once in a multi
280*6777b538SAndroid Build Coastguard Worker     // threaded environment.
281*6777b538SAndroid Build Coastguard Worker     std::once_flag create_next_chunk_flag;
282*6777b538SAndroid Build Coastguard Worker   };
283*6777b538SAndroid Build Coastguard Worker 
284*6777b538SAndroid Build Coastguard Worker   template <size_t LowerNumberOfItems,
285*6777b538SAndroid Build Coastguard Worker             size_t UpperNumberOfItems,
286*6777b538SAndroid Build Coastguard Worker             size_t NumberOfBytes>
CalculateEffectiveNumberOfItemsBinSearchThreadLocalStorage287*6777b538SAndroid Build Coastguard Worker   static constexpr size_t CalculateEffectiveNumberOfItemsBinSearch() {
288*6777b538SAndroid Build Coastguard Worker     if constexpr (LowerNumberOfItems == UpperNumberOfItems) {
289*6777b538SAndroid Build Coastguard Worker       return LowerNumberOfItems;
290*6777b538SAndroid Build Coastguard Worker     }
291*6777b538SAndroid Build Coastguard Worker 
292*6777b538SAndroid Build Coastguard Worker     constexpr size_t CurrentNumberOfItems =
293*6777b538SAndroid Build Coastguard Worker         (UpperNumberOfItems - LowerNumberOfItems) / 2 + LowerNumberOfItems;
294*6777b538SAndroid Build Coastguard Worker 
295*6777b538SAndroid Build Coastguard Worker     if constexpr (sizeof(ChunkT<CurrentNumberOfItems>) > NumberOfBytes) {
296*6777b538SAndroid Build Coastguard Worker       return CalculateEffectiveNumberOfItemsBinSearch<
297*6777b538SAndroid Build Coastguard Worker           LowerNumberOfItems, CurrentNumberOfItems, NumberOfBytes>();
298*6777b538SAndroid Build Coastguard Worker     }
299*6777b538SAndroid Build Coastguard Worker 
300*6777b538SAndroid Build Coastguard Worker     if constexpr (sizeof(ChunkT<CurrentNumberOfItems + 1>) < NumberOfBytes) {
301*6777b538SAndroid Build Coastguard Worker       return CalculateEffectiveNumberOfItemsBinSearch<
302*6777b538SAndroid Build Coastguard Worker           CurrentNumberOfItems + 1, UpperNumberOfItems, NumberOfBytes>();
303*6777b538SAndroid Build Coastguard Worker     }
304*6777b538SAndroid Build Coastguard Worker 
305*6777b538SAndroid Build Coastguard Worker     return CurrentNumberOfItems;
306*6777b538SAndroid Build Coastguard Worker   }
307*6777b538SAndroid Build Coastguard Worker 
308*6777b538SAndroid Build Coastguard Worker   // Calculate the maximum number of items we can store in one chunk without the
309*6777b538SAndroid Build Coastguard Worker   // size of the chunk exceeding NumberOfBytes. To avoid things like alignment
310*6777b538SAndroid Build Coastguard Worker   // and packing tampering with the calculation, instead of calculating the
311*6777b538SAndroid Build Coastguard Worker   // correct number of items we use sizeof-operator against ChunkT to search for
312*6777b538SAndroid Build Coastguard Worker   // the correct size. Unfortunately, the number of recursions is limited by the
313*6777b538SAndroid Build Coastguard Worker   // compiler. Therefore, we use a binary search instead of a simple linear
314*6777b538SAndroid Build Coastguard Worker   // search.
315*6777b538SAndroid Build Coastguard Worker   template <size_t MinimumNumberOfItems, size_t NumberOfBytes>
CalculateEffectiveNumberOfItemsThreadLocalStorage316*6777b538SAndroid Build Coastguard Worker   static constexpr size_t CalculateEffectiveNumberOfItems() {
317*6777b538SAndroid Build Coastguard Worker     if constexpr (sizeof(ChunkT<MinimumNumberOfItems>) < NumberOfBytes) {
318*6777b538SAndroid Build Coastguard Worker       constexpr size_t LowerNumberOfItems = MinimumNumberOfItems;
319*6777b538SAndroid Build Coastguard Worker       constexpr size_t UpperNumberOfItems =
320*6777b538SAndroid Build Coastguard Worker           NumberOfBytes / sizeof(PayloadType) + 1;
321*6777b538SAndroid Build Coastguard Worker       return CalculateEffectiveNumberOfItemsBinSearch<
322*6777b538SAndroid Build Coastguard Worker           LowerNumberOfItems, UpperNumberOfItems, NumberOfBytes>();
323*6777b538SAndroid Build Coastguard Worker     }
324*6777b538SAndroid Build Coastguard Worker 
325*6777b538SAndroid Build Coastguard Worker     return MinimumNumberOfItems;
326*6777b538SAndroid Build Coastguard Worker   }
327*6777b538SAndroid Build Coastguard Worker 
328*6777b538SAndroid Build Coastguard Worker  public:
329*6777b538SAndroid Build Coastguard Worker   // The minimum number of items per chunk. It should be high enough to
330*6777b538SAndroid Build Coastguard Worker   // accommodate most items in the root chunk whilst not wasting to much space
331*6777b538SAndroid Build Coastguard Worker   // on unnecessary items.
332*6777b538SAndroid Build Coastguard Worker   static constexpr size_t MinimumNumberOfItemsPerChunk = 75;
333*6777b538SAndroid Build Coastguard Worker   // The effective number of items per chunk. We use the AllocationChunkSize as
334*6777b538SAndroid Build Coastguard Worker   // a hint to calculate to effective number of items so we occupy one of these
335*6777b538SAndroid Build Coastguard Worker   // memory chunks to the maximum extent possible.
336*6777b538SAndroid Build Coastguard Worker   static constexpr size_t ItemsPerChunk =
337*6777b538SAndroid Build Coastguard Worker       CalculateEffectiveNumberOfItems<MinimumNumberOfItemsPerChunk,
338*6777b538SAndroid Build Coastguard Worker                                       AllocationChunkSize>();
339*6777b538SAndroid Build Coastguard Worker 
340*6777b538SAndroid Build Coastguard Worker  private:
341*6777b538SAndroid Build Coastguard Worker   using Chunk = ChunkT<ItemsPerChunk>;
342*6777b538SAndroid Build Coastguard Worker 
343*6777b538SAndroid Build Coastguard Worker   static_assert(ItemsPerChunk >= MinimumNumberOfItemsPerChunk);
344*6777b538SAndroid Build Coastguard Worker 
345*6777b538SAndroid Build Coastguard Worker   // Mark an item's slot ready for reuse. This function is used as thread
346*6777b538SAndroid Build Coastguard Worker   // termination function in the TLS system. We do not destroy anything at this
347*6777b538SAndroid Build Coastguard Worker   // point but simply mark the slot as unused.
MarkSlotAsFreeThreadLocalStorage348*6777b538SAndroid Build Coastguard Worker   static void MarkSlotAsFree(void* data) {
349*6777b538SAndroid Build Coastguard Worker     // We always store SingleSlots in the TLS system. Therefore, we cast to
350*6777b538SAndroid Build Coastguard Worker     // SingleSlot and reset the is_used flag.
351*6777b538SAndroid Build Coastguard Worker     auto* const slot = static_cast<SingleSlot*>(data);
352*6777b538SAndroid Build Coastguard Worker 
353*6777b538SAndroid Build Coastguard Worker     // We might be called in the course of handling a memory allocation.
354*6777b538SAndroid Build Coastguard Worker     // Therefore, do not use CHECK since it might allocate and cause a
355*6777b538SAndroid Build Coastguard Worker     // recursion.
356*6777b538SAndroid Build Coastguard Worker     TLS_RAW_CHECK("Received an invalid slot.",
357*6777b538SAndroid Build Coastguard Worker                   slot && slot->is_used.test_and_set());
358*6777b538SAndroid Build Coastguard Worker 
359*6777b538SAndroid Build Coastguard Worker     slot->is_used.clear(std::memory_order_relaxed);
360*6777b538SAndroid Build Coastguard Worker   }
361*6777b538SAndroid Build Coastguard Worker 
362*6777b538SAndroid Build Coastguard Worker   // Perform common initialization during construction of an instance.
InitializeThreadLocalStorage363*6777b538SAndroid Build Coastguard Worker   void Initialize(const std::string_view instance_id) {
364*6777b538SAndroid Build Coastguard Worker     // The constructor must be called outside of the allocation path. Therefore,
365*6777b538SAndroid Build Coastguard Worker     // it is secure to verify with CHECK.
366*6777b538SAndroid Build Coastguard Worker 
367*6777b538SAndroid Build Coastguard Worker     // Passing MarkSlotAsFree as thread_termination_function we ensure the
368*6777b538SAndroid Build Coastguard Worker     // slot/item assigned to the finished thread will be returned to the pool of
369*6777b538SAndroid Build Coastguard Worker     // unused items.
370*6777b538SAndroid Build Coastguard Worker     CHECK(dereference(tls_system_).Setup(&MarkSlotAsFree, instance_id));
371*6777b538SAndroid Build Coastguard Worker   }
372*6777b538SAndroid Build Coastguard Worker 
AllocateAndInitializeChunkThreadLocalStorage373*6777b538SAndroid Build Coastguard Worker   Chunk* AllocateAndInitializeChunk() {
374*6777b538SAndroid Build Coastguard Worker     void* const uninitialized_memory =
375*6777b538SAndroid Build Coastguard Worker         dereference(allocator_).AllocateMemory(sizeof(Chunk));
376*6777b538SAndroid Build Coastguard Worker 
377*6777b538SAndroid Build Coastguard Worker     // We might be called in the course of handling a memory allocation. We do
378*6777b538SAndroid Build Coastguard Worker     // not use CHECK since they might allocate and cause a recursion.
379*6777b538SAndroid Build Coastguard Worker     TLS_RAW_CHECK("Failed to allocate memory for new chunk.",
380*6777b538SAndroid Build Coastguard Worker                   uninitialized_memory != nullptr);
381*6777b538SAndroid Build Coastguard Worker 
382*6777b538SAndroid Build Coastguard Worker     return new (uninitialized_memory) Chunk{};
383*6777b538SAndroid Build Coastguard Worker   }
384*6777b538SAndroid Build Coastguard Worker 
FreeAndDeallocateChunkForTestingThreadLocalStorage385*6777b538SAndroid Build Coastguard Worker   void FreeAndDeallocateChunkForTesting(Chunk* chunk_to_erase) {
386*6777b538SAndroid Build Coastguard Worker     chunk_to_erase->~Chunk();
387*6777b538SAndroid Build Coastguard Worker 
388*6777b538SAndroid Build Coastguard Worker     // FreeAndDeallocateChunkForTesting must be called outside of the allocation
389*6777b538SAndroid Build Coastguard Worker     // path. Therefore, it is secure to verify with CHECK.
390*6777b538SAndroid Build Coastguard Worker     CHECK(dereference(allocator_)
391*6777b538SAndroid Build Coastguard Worker               .FreeMemoryForTesting(chunk_to_erase, sizeof(Chunk)));
392*6777b538SAndroid Build Coastguard Worker   }
393*6777b538SAndroid Build Coastguard Worker 
394*6777b538SAndroid Build Coastguard Worker   // Find a free slot in the passed chunk, reserve it and return it to the
395*6777b538SAndroid Build Coastguard Worker   // caller. If no free slot can be found, head on to the next chunk. If the
396*6777b538SAndroid Build Coastguard Worker   // next chunk doesn't exist, create it.
FindAndAllocateFreeSlotThreadLocalStorage397*6777b538SAndroid Build Coastguard Worker   SingleSlot* FindAndAllocateFreeSlot(Chunk* const chunk) {
398*6777b538SAndroid Build Coastguard Worker     SingleSlot* const slot = std::find_if_not(
399*6777b538SAndroid Build Coastguard Worker         std::begin(chunk->slots), std::end(chunk->slots),
400*6777b538SAndroid Build Coastguard Worker         [](SingleSlot& candidate_slot) {
401*6777b538SAndroid Build Coastguard Worker           return candidate_slot.is_used.test_and_set(std::memory_order_relaxed);
402*6777b538SAndroid Build Coastguard Worker         });
403*6777b538SAndroid Build Coastguard Worker 
404*6777b538SAndroid Build Coastguard Worker     // So we found a slot. Happily return it to the caller.
405*6777b538SAndroid Build Coastguard Worker     if (slot != std::end(chunk->slots)) {
406*6777b538SAndroid Build Coastguard Worker       return slot;
407*6777b538SAndroid Build Coastguard Worker     }
408*6777b538SAndroid Build Coastguard Worker 
409*6777b538SAndroid Build Coastguard Worker     // Ok, there are no more free slots in this chunk. First, ensure the next
410*6777b538SAndroid Build Coastguard Worker     // chunk is valid and create one if necessary.
411*6777b538SAndroid Build Coastguard Worker     std::call_once(chunk->create_next_chunk_flag, [&] {
412*6777b538SAndroid Build Coastguard Worker       // From https://eel.is/c++draft/thread.once.callonce#3
413*6777b538SAndroid Build Coastguard Worker       //
414*6777b538SAndroid Build Coastguard Worker       // Synchronization: For any given once_­flag: all active executions occur
415*6777b538SAndroid Build Coastguard Worker       // in a total order; completion of an active execution synchronizes with
416*6777b538SAndroid Build Coastguard Worker       // the start of the next one in this total order; and the returning
417*6777b538SAndroid Build Coastguard Worker       // execution synchronizes with the return from all passive executions.
418*6777b538SAndroid Build Coastguard Worker       //
419*6777b538SAndroid Build Coastguard Worker       // Therefore, we do only a relaxed store here, call_once synchronizes with
420*6777b538SAndroid Build Coastguard Worker       // other threads.
421*6777b538SAndroid Build Coastguard Worker       chunk->next_chunk.store(AllocateAndInitializeChunk(),
422*6777b538SAndroid Build Coastguard Worker                               std::memory_order_relaxed);
423*6777b538SAndroid Build Coastguard Worker     });
424*6777b538SAndroid Build Coastguard Worker 
425*6777b538SAndroid Build Coastguard Worker     return FindAndAllocateFreeSlot(chunk->next_chunk);
426*6777b538SAndroid Build Coastguard Worker   }
427*6777b538SAndroid Build Coastguard Worker 
428*6777b538SAndroid Build Coastguard Worker   template <bool IsDestructibleForTestingP = IsDestructibleForTesting>
429*6777b538SAndroid Build Coastguard Worker   typename std::enable_if<IsDestructibleForTestingP>::type
TearDownForTestingThreadLocalStorage430*6777b538SAndroid Build Coastguard Worker   TearDownForTesting() {
431*6777b538SAndroid Build Coastguard Worker     // The destructor must be called outside of the allocation path. Therefore,
432*6777b538SAndroid Build Coastguard Worker     // it is secure to verify with CHECK.
433*6777b538SAndroid Build Coastguard Worker 
434*6777b538SAndroid Build Coastguard Worker     // All accessing threads must be terminated by now. For additional security
435*6777b538SAndroid Build Coastguard Worker     // we tear down the TLS system first. This way we ensure that
436*6777b538SAndroid Build Coastguard Worker     // MarkSlotAsFree is not called anymore and we have no accesses from the
437*6777b538SAndroid Build Coastguard Worker     // TLS system's side.
438*6777b538SAndroid Build Coastguard Worker     CHECK(dereference(tls_system_).TearDownForTesting());
439*6777b538SAndroid Build Coastguard Worker 
440*6777b538SAndroid Build Coastguard Worker     // Delete all data chunks.
441*6777b538SAndroid Build Coastguard Worker     for (auto* chunk = root_.load(); chunk != nullptr;) {
442*6777b538SAndroid Build Coastguard Worker       auto* next_chunk = chunk->next_chunk.load();
443*6777b538SAndroid Build Coastguard Worker       FreeAndDeallocateChunkForTesting(chunk);
444*6777b538SAndroid Build Coastguard Worker       chunk = next_chunk;
445*6777b538SAndroid Build Coastguard Worker     }
446*6777b538SAndroid Build Coastguard Worker   }
447*6777b538SAndroid Build Coastguard Worker 
448*6777b538SAndroid Build Coastguard Worker   // Reset a single item to its default value.
449*6777b538SAndroid Build Coastguard Worker   // Since items are re-used, they may be accessed from different threads,
450*6777b538SAndroid Build Coastguard Worker   // causing TSan to trigger. Therefore, the reset is exempt from TSan
451*6777b538SAndroid Build Coastguard Worker   // instrumentation.
ResetThreadLocalStorage452*6777b538SAndroid Build Coastguard Worker   DISABLE_TSAN_INSTRUMENTATION void Reset(PayloadType& item) { item = {}; }
453*6777b538SAndroid Build Coastguard Worker 
454*6777b538SAndroid Build Coastguard Worker   AllocatorType allocator_;
455*6777b538SAndroid Build Coastguard Worker   TLSSystemType tls_system_;
456*6777b538SAndroid Build Coastguard Worker   std::atomic<Chunk*> const root_;
457*6777b538SAndroid Build Coastguard Worker };
458*6777b538SAndroid Build Coastguard Worker 
459*6777b538SAndroid Build Coastguard Worker }  // namespace internal
460*6777b538SAndroid Build Coastguard Worker 
461*6777b538SAndroid Build Coastguard Worker // The ThreadLocalStorage visible to the user. This uses the internal default
462*6777b538SAndroid Build Coastguard Worker // allocator and TLS system.
463*6777b538SAndroid Build Coastguard Worker template <typename StorageType,
464*6777b538SAndroid Build Coastguard Worker           typename AllocatorType = internal::DefaultAllocator,
465*6777b538SAndroid Build Coastguard Worker           typename TLSSystemType = internal::DefaultTLSSystem,
466*6777b538SAndroid Build Coastguard Worker           size_t AllocationChunkSize = AllocatorType::AllocationChunkSize,
467*6777b538SAndroid Build Coastguard Worker           bool IsDestructibleForTesting = false>
468*6777b538SAndroid Build Coastguard Worker using ThreadLocalStorage =
469*6777b538SAndroid Build Coastguard Worker     internal::ThreadLocalStorage<StorageType,
470*6777b538SAndroid Build Coastguard Worker                                  AllocatorType,
471*6777b538SAndroid Build Coastguard Worker                                  TLSSystemType,
472*6777b538SAndroid Build Coastguard Worker                                  AllocationChunkSize,
473*6777b538SAndroid Build Coastguard Worker                                  IsDestructibleForTesting>;
474*6777b538SAndroid Build Coastguard Worker 
475*6777b538SAndroid Build Coastguard Worker }  // namespace base::allocator::dispatcher
476*6777b538SAndroid Build Coastguard Worker 
477*6777b538SAndroid Build Coastguard Worker #undef TLS_RAW_CHECK_IMPL
478*6777b538SAndroid Build Coastguard Worker #undef TLS_RAW_CHECK
479*6777b538SAndroid Build Coastguard Worker #undef STR
480*6777b538SAndroid Build Coastguard Worker #undef STR_HELPER
481*6777b538SAndroid Build Coastguard Worker 
482*6777b538SAndroid Build Coastguard Worker #endif  // USE_LOCAL_TLS_EMULATION()
483*6777b538SAndroid Build Coastguard Worker #endif  // BASE_ALLOCATOR_DISPATCHER_TLS_H_
484